package cn.bonoon.kernel.bytecode.asm;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.springframework.asm.Label;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Type;
import org.springframework.context.ApplicationContext;

import cn.bonoon.kernel.IOptionArray;
import cn.bonoon.kernel.IdGenerator;
import cn.bonoon.kernel.annotations.AppendProperty;
import cn.bonoon.kernel.annotations.ArraySeparator;
import cn.bonoon.kernel.annotations.Cipher;
import cn.bonoon.kernel.annotations.Cutoff;
import cn.bonoon.kernel.annotations.FormatString;
import cn.bonoon.kernel.annotations.FormatValueType;
import cn.bonoon.kernel.annotations.ObjectClass;
import cn.bonoon.kernel.annotations.ReadModel;
import cn.bonoon.kernel.annotations.Secrecy;
import cn.bonoon.kernel.annotations.TransformField;
import cn.bonoon.kernel.annotations.ValueReader;
import cn.bonoon.kernel.bytecode.EntityReader;
import cn.bonoon.kernel.descriptors.DescriptorFactory;
import cn.bonoon.kernel.descriptors.EntityDescriptor;
import cn.bonoon.kernel.descriptors.EntityPropertyAccessor;
import cn.bonoon.kernel.descriptors.ManyPropertyAccessor;
import cn.bonoon.kernel.descriptors.ObjectDescriptor;
import cn.bonoon.kernel.descriptors.ObjectPropertyAccessor;
import cn.bonoon.kernel.descriptors.OnePropertyAccessor;
import cn.bonoon.kernel.events.ReadEvent;
import cn.bonoon.kernel.support.CipherGenerator;
import cn.bonoon.kernel.support.entities.AbstractEntity;
import cn.bonoon.kernel.util.StringHelper;

/**
 * <pre>
 * 读取值的时候，需要处理几种特殊的数据类型：
 * 1.列表的数据{@link cn.bonoon.kernel.support.models.AbstractItem AbstractItem}
 * 2.树型数据结构{@link cn.bonoon.kernel.support.models.AbstractNode AbstractNode}
 * 3.可异步加载的树型结构的数据{@link cn.bonoon.kernel.support.models.AbstractAjaxNode AbstractAjaxNode}
 * </pre>
 * @author jackson
 *
 */
public class ASMReaderBuilder extends ASMAbstractConvertBuilder<EntityReader>{
	private final ReadModel read;
	private final String readerName = IdGenerator.build();
	private final String findName 	= IdGenerator.build();
	private final String initReader;
	private String readerDes, findDes;
	
	
	public ASMReaderBuilder(ReadModel read, String initReader, ApplicationContext applicationContext, ObjectDescriptor objectDescriptor, EntityDescriptor entityDescriptor) {
		super(applicationContext, EntityReader.class, objectDescriptor, entityDescriptor, ReadEvent.class);
		this.read = read;
		this.initReader = initReader;
	}
	
	private void initObject(MethodVisitor reader, int entityPoint, Class<?> parameterType) throws Exception{
		try{
			Constructor<?> con = objectDescriptor.getConstructor(parameterType);
			reader.visitTypeInsn(NEW, objectPath);
			reader.visitInsn(DUP);
			reader.visitVarInsn(ALOAD, entityPoint);
			reader.visitMethodInsn(INVOKESPECIAL, objectPath, "<init>", Type.getConstructorDescriptor(con), false); 
		}catch(Exception t){
			reader.visitTypeInsn(NEW, objectPath);
			reader.visitInsn(DUP);
			reader.visitMethodInsn(INVOKESPECIAL, objectPath, "<init>", "()V", false); 
		}
	}
	
	private ASMEvent read_start(Class<?> type){
		MethodVisitor reader = visitMethod(ACC_PRIVATE, readerName, readerDes, null, null);
		ASMEvent event = new ASMEvent(reader, 3, 2, 4);
		reader.visitCode();
		try{
			Method init = objectDescriptor.getMethod(initReader, type);
			reader.visitVarInsn(ALOAD, event.setterPoint);
			reader.visitVarInsn(ALOAD, event.getterPoint);
			reader.visitMethodInsn(INVOKEVIRTUAL, objectPath, init.getName(), Type.getMethodDescriptor(init), false);
		}catch (Exception e) {
			//没有使用初始化函数的方法
		}
		return event;
	}
	
	private void read_end(ASMEvent event){
		event.writer.visitVarInsn(ALOAD, event.setterPoint);
		event.writer.visitInsn(ARETURN);
		event.writer.visitMaxs(0, 0);
		event.writer.visitEnd();
	}
	
	@Override
	protected void internalBuild() throws Exception {
		Class<?> type;
		MethodVisitor reader;
//		eventPoint = 1;
		if(read == ReadModel.OPTIMIZE){
			NameMapped root = new NameMapped();
			type = Object[].class;
			String entityPath = Type.getInternalName(type);

			readerDes = "(L" + eventPath + ";" + entityPath + "L" + objectPath + ";)L" + objectPath + ";";
			findDes = "(L" + managerPath + ";Ljava/lang/Long;)" + entityPath;
			reader = _visitMethod("read", ReadEvent.class, Object.class, Object.class);
			Label ifeq = _0(reader, entityPath, 2);
			_0(reader, entityPath);
			_0(reader, ifeq);

			reader = _visitMethod("read", ReadEvent.class, Object.class);
			ifeq = _0(reader, entityPath, 2);
			reader.visitVarInsn(ALOAD, 2);
			reader.visitTypeInsn(CHECKCAST, entityPath);
			reader.visitVarInsn(ASTORE, 3);
			_0(type, reader, 3);
			_0(reader, ifeq);

			reader = _visitMethod("read", ReadEvent.class, EntityManager.class, Long.class);
			reader.visitVarInsn(ALOAD, 0);
			reader.visitVarInsn(ALOAD, 2);
			reader.visitVarInsn(ALOAD, 3);
			reader.visitMethodInsn(INVOKEVIRTUAL, classPath, findName, findDes, false);
			reader.visitVarInsn(ASTORE, 4);
			ifeq = _0(reader, entityPath, 4);
			_0(type, reader, 4);
			_0(reader, ifeq);
			
			ASMEvent event = read_start(type);
			reader = event.writer;
			try{
				_0(event, Long.class);
			}catch (Exception e) {
				try{
					_0(event, long.class);
				}catch (Exception ne) { /*没有定义id*/ }
			}
			for(ObjectPropertyAccessor objectProperty : objectDescriptor.values()){
				if(objectProperty.isInvalid()) continue;
				TransformField transformField = objectProperty.getAnnotation(TransformField.class);
				String name;
				if(null == transformField){
					name = objectProperty.getName();
				}else if(!transformField.readable()){
					continue;
				}else{
					name = transformField.value();
					if(name.isEmpty() || ".".equals(name) || "[".equals(name)){
						name = objectProperty.getName();
					}else{
						if(name.startsWith(".")){
							name = objectProperty.getName() + name;
						}
						if(name.endsWith(".")){
							name += objectProperty.getName();
						}
					}
				}
				NameMapped tnm = root.append(entityDescriptor, name);
				if(null == tnm) continue;
				_0(name, objectProperty, tnm, root).init().parseProperty(event);
			}
			read_end(event);
			StringBuilder selectProperties = new StringBuilder();
			root.toString(selectProperties);
			reader = visitMethod(ACC_PUBLIC, "properties", "()Ljava/lang/String;", null, null);
			reader.visitCode();
			reader.visitLdcInsn(selectProperties.toString());
			reader.visitInsn(ARETURN);
			reader.visitMaxs(0, 0);
			reader.visitEnd();
			
			constructor.visitVarInsn(ALOAD, 0);
			constructor.visitInsn(ICONST_0);
			constructor.visitFieldInsn(PUTFIELD, classPath, "optimize", "Z");

			// TODO ------下面是根据id加载数据库字段，返回的结果为数组类型
			reader = visitMethod(ACC_PRIVATE, findName, findDes, null, null);
			reader.visitCode();
			String qldes = "java/lang/StringBuilder";
			reader.visitVarInsn(ALOAD, 1);
			reader.visitTypeInsn(NEW, qldes);  
			reader.visitInsn(DUP);
			reader.visitLdcInsn("select ");
			reader.visitMethodInsn(INVOKESPECIAL, qldes, "<init>", "(Ljava/lang/String;)V", false);
			reader.visitVarInsn(ALOAD, 0);
			reader.visitMethodInsn(INVOKEVIRTUAL, classPath, "properties", "()Ljava/lang/String;", false);
			reader.visitMethodInsn(INVOKEVIRTUAL, qldes, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
			reader.visitLdcInsn(" from " + entityName() + " x where x.id=?");
			reader.visitMethodInsn(INVOKEVIRTUAL, qldes, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
			reader.visitMethodInsn(INVOKEVIRTUAL, qldes, "toString", "()Ljava/lang/String;", false);
			reader.visitMethodInsn(INVOKEINTERFACE, managerPath, "createQuery", "(Ljava/lang/String;)Ljavax/persistence/Query;", true);
			reader.visitInsn(ICONST_1);
			reader.visitVarInsn(ALOAD, 2);
			reader.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/Query", "setParameter", "(ILjava/lang/Object;)Ljavax/persistence/Query;", true);
			reader.visitMethodInsn(INVOKEINTERFACE, "javax/persistence/Query", "getSingleResult", "()Ljava/lang/Object;", true);
			reader.visitTypeInsn(CHECKCAST, entityPath);
			reader.visitInsn(ARETURN);
			reader.visitMaxs(0, 0);
			reader.visitEnd();
		}else{
			type = entityDescriptor.toClass();
			readerDes = "(L" + eventPath + ";L" + entityPath + ";L" + objectPath + ";)L" + objectPath + ";";
			findDes = "(L" + managerPath + ";Ljava/lang/Long;)L" + entityPath + ";";
			reader = _visitMethod("read", ReadEvent.class, Object.class, Object.class);
			_0(reader, entityPath);
			reader.visitMaxs(0, 0);
			reader.visitEnd();

			reader = _visitMethod("read", ReadEvent.class, Object.class);
			reader.visitVarInsn(ALOAD, 2);
			reader.visitTypeInsn(CHECKCAST, entityPath);
			reader.visitVarInsn(ASTORE, 3);
			_0(type, reader, 3);
			reader.visitMaxs(0, 0);
			reader.visitEnd();

			reader = _visitMethod("read", ReadEvent.class, EntityManager.class, Long.class);
			reader.visitVarInsn(ALOAD, 0);
			reader.visitVarInsn(ALOAD, 2);
			reader.visitVarInsn(ALOAD, 3);
			reader.visitMethodInsn(INVOKEVIRTUAL, classPath, findName, findDes, false);
			reader.visitVarInsn(ASTORE, 4);
			_0(type, reader, 4);
			reader.visitMaxs(0, 0);
			reader.visitEnd();
			
			ASMEvent event = read_start(type);
			reader = event.writer;
			try{
				_0(entityPath, event, Long.class);
			}catch (Exception e) {
				try{
					_0(entityPath, event, long.class);
				}catch (Exception ne){ /*没有定义id*/ }
			}
			//用来调整通过其实对象取值的
			Map<String, PropertyReaderInitialize> initProperties = new HashMap<String, PropertyReaderInitialize>(2);
			OUTER: for(ObjectPropertyAccessor objectProperty : objectDescriptor.values()){
				if(objectProperty.isInvalid()) continue;
				TransformField transformField = objectProperty.getAnnotation(TransformField.class);
				if(null == transformField){
					String name = objectProperty.getName();
					EntityPropertyAccessor entityProperty = entityDescriptor.get(name);
					if(!(entityProperty instanceof ManyPropertyAccessor)){
						_parseRelatedEntity(name, objectProperty, entityProperty, initProperties, event);
					}
					continue;
				}
				if(!transformField.readable()) continue;
				String name = transformField.value();
				if(name.isEmpty()|| ".".equals(name) || "[".equals(name)){ 
					name = objectProperty.getName();
					_parseRelatedEntity(name, objectProperty, entityDescriptor.get(name), initProperties, event);
					continue;
				}
				if(name.endsWith(".") || name.endsWith("[")){
					name += objectProperty.getName();
				}else if(name.startsWith(".") || name.startsWith("[")){
					name = objectProperty.getName() + name;
				}
				EntityPropertyAccessor entityProperty = entityDescriptor.get(name);
				if(_parseRelatedEntity(name, objectProperty, entityProperty, initProperties, event)){
					continue;
				}
				String[] names = name.split("\\.");
				if(names.length > 1){
					EntityDescriptor entityDescriptor = this.entityDescriptor;
					String tem = names[0], mappath = tem;
					PropertyReaderInitialize toPre = initProperties.get(mappath);
					EntityPropertyAccessor epa;
					if(toPre == null){
						epa = entityDescriptor.get(tem);
						if(null == epa) continue;//定义的格式不正确，无法解释
						toPre = new PropertyReaderInitializeImpl(initProperties, epa);
					}
					int i = 1, l = names.length - 1;
					for(; i < l; i++){
						tem += '.' + names[i];
						mappath += '.' + names[i];
						PropertyReaderInitialize curr = toPre.get(mappath);
						if(null == curr){
							epa = entityDescriptor.get(tem);
							if(null == epa){
								//可能需要使用关联实体的情况
								entityDescriptor = DescriptorFactory.entityDescriptor(toPre.getType());
								tem = names[i];
								epa = entityDescriptor.get(tem);
								if(null == epa) continue OUTER;
							}
							curr = new PropertyReaderInitializeImpl(toPre, epa);
							toPre.add(mappath, curr);
						}
						toPre = curr;
					}
					tem += '.' + names[i];
					entityProperty = entityDescriptor.get(tem);
					if(null == entityProperty){
						tem = names[i];
						//可能需要使用关联实体的情况
						entityDescriptor = DescriptorFactory.entityDescriptor(toPre.getType());
						entityProperty = entityDescriptor.get(tem);
						if(null == entityProperty) continue;
					}
					if(entityProperty instanceof OnePropertyAccessor){
						mappath += '.' + names[i];
						PropertyReaderInitialize curr = toPre.get(mappath);
						if(null == curr){
							curr = new PropertyReaderInitializeImpl(toPre, entityProperty);
							toPre.add(mappath, curr);
						}
						ReadEntityParser erp = new ReadEntityParser(this, name, objectProperty, (OnePropertyAccessor)entityProperty, curr);
						curr.add(erp.init());
					} else if(entityProperty instanceof ManyPropertyAccessor){
						ManyPropertyAccessor mpa = (ManyPropertyAccessor)entityProperty;
						mappath += '.' + names[i];
						CollctionReaderInitializeImpl curr = (CollctionReaderInitializeImpl)toPre.get(mappath);
						if(null == curr){
							curr = new CollctionReaderInitializeImpl(toPre, mpa);
							toPre.add(mappath, curr);
							toPre = curr;
						}
						ReadCollectionParser crp = new ReadCollectionParser(this, name, objectProperty, mpa, curr);
						curr.add(crp.init());
					}else{
						PropertyReader asmrp = _0(name, objectProperty, entityProperty, toPre);
						toPre.add(asmrp.init());
					}
					continue;
				}
				int cp = name.indexOf('[');
				if(cp > 0){
					String prename = name.substring(0, cp), lastname = name.substring(cp + 1);
					entityProperty = entityDescriptor.get(prename);
					if(entityProperty instanceof ManyPropertyAccessor){
						ManyPropertyAccessor mpa = (ManyPropertyAccessor)entityProperty;
						CollctionReaderInitializeImpl toPre = _0(entityProperty, initProperties, mpa, prename);
						ReadCollectionParser crp = new ReadCollectionParser(this, prename, lastname, objectProperty, mpa, toPre);
						toPre.add(crp.init());
						continue;
					}
					names = prename.split("\\.");//TODO
					if(names.length > 1){
						EntityDescriptor entityDescriptor = this.entityDescriptor;
						String tem = names[0], mappath = tem;
						PropertyReaderInitialize toPre = initProperties.get(mappath);
						EntityPropertyAccessor epa;
						if(toPre == null){
							epa = entityDescriptor.get(tem);
							if(null == epa) continue;//定义的格式不正确，无法解释
							toPre = new PropertyReaderInitializeImpl(initProperties, epa);
						}
						int i = 1, l = names.length - 1;
						for(; i < l; i++){
							tem += '.' + names[i];
							mappath += '.' + names[i];
							PropertyReaderInitialize curr = toPre.get(mappath);
							if(null == curr){
								epa = entityDescriptor.get(tem);
								if(null == epa){
									//可能需要使用关联实体的情况
									entityDescriptor = DescriptorFactory.entityDescriptor(toPre.getType());
									tem = names[i];
									epa = entityDescriptor.get(tem);
									if(null == epa) continue OUTER;
								}
								curr = new PropertyReaderInitializeImpl(toPre, epa);
								toPre.add(mappath, curr);
							}
							toPre = curr;
						}
						tem += '.' + names[i];
						entityProperty = entityDescriptor.get(tem);
						if(null == entityProperty){
							tem = names[i];
							//可能需要使用关联实体的情况
							entityDescriptor = DescriptorFactory.entityDescriptor(toPre.getType());
							entityProperty = entityDescriptor.get(tem);
							if(null == entityProperty) continue;
						}
						if(entityProperty instanceof ManyPropertyAccessor){
							ManyPropertyAccessor mpa = (ManyPropertyAccessor)entityProperty;
							mappath += '.' + names[i];
							CollctionReaderInitializeImpl curr = (CollctionReaderInitializeImpl)toPre.get(mappath);
							if(null == curr){
								curr = new CollctionReaderInitializeImpl(toPre, mpa);
								toPre.add(mappath, curr);
								toPre = curr;
							}
							ReadCollectionParser crp = new ReadCollectionParser(this, prename, lastname, objectProperty, mpa, curr);
							curr.add(crp.init());
						}
					}
				}
			}
			
			for(PropertyReaderInitialize rip : initProperties.values()){
				rip.parseProperty(event);
			}
			
			read_end(event);
			
			//------下面是根据id加载实体，返回的结果为数据库实体类型
			reader = visitMethod(ACC_PRIVATE, findName, findDes, null, null);
			reader.visitCode();
			reader.visitVarInsn(ALOAD, 1);
			reader.visitLdcInsn(Type.getType(type));
			reader.visitVarInsn(ALOAD, 2);
			visitMethodFind(reader);
			reader.visitTypeInsn(CHECKCAST, entityPath);
			_return(reader, ARETURN);
		}
	}
	private void _0(MethodVisitor reader, Label ifeq) {
		reader.visitLabel(ifeq);
		reader.visitInsn(ACONST_NULL);
		reader.visitInsn(ARETURN);
		reader.visitMaxs(0, 0);
		reader.visitEnd();
	}
	private Label _0(MethodVisitor reader, String entityPath, int point) {
		Label ifeq;
		reader.visitVarInsn(ALOAD, point);
		reader.visitTypeInsn(INSTANCEOF, entityPath);
		ifeq = new Label();
		reader.visitJumpInsn(IFEQ, ifeq);
		return ifeq;
	}
	private void _0(MethodVisitor reader, String entityPath) {
		reader.visitVarInsn(ALOAD, 0);
		reader.visitVarInsn(ALOAD, 1);
		reader.visitVarInsn(ALOAD, 2);
		reader.visitTypeInsn(CHECKCAST, entityPath);
		reader.visitVarInsn(ALOAD, 3);
		reader.visitTypeInsn(CHECKCAST, objectPath);
		reader.visitMethodInsn(INVOKEVIRTUAL, classPath, readerName, readerDes, false);
		reader.visitInsn(ARETURN);
	}
	private void _0(Class<?> type, MethodVisitor reader, int entityPoint) throws Exception {
		reader.visitVarInsn(ALOAD, 0);
		reader.visitVarInsn(ALOAD, 1);
		reader.visitVarInsn(ALOAD, entityPoint);
		initObject(reader, entityPoint, type);
		reader.visitMethodInsn(INVOKEVIRTUAL, classPath, readerName, readerDes, false);
		reader.visitInsn(ARETURN);
	}
	private void _0(ASMEvent event, Class<?> cls) throws Exception {
		Method id = objectDescriptor.getMethod("setId", Long.class);
		MethodVisitor reader = event.writer;
		reader.visitVarInsn(ALOAD, event.setterPoint);
		reader.visitVarInsn(ALOAD, 1);
		reader.visitVarInsn(ALOAD, event.getterPoint);
		reader.visitInsn(ICONST_0);
		reader.visitInsn(AALOAD);
		reader.visitTypeInsn(CHECKCAST, "java/lang/Number");
		reader.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "longValue", "()J", false);
		reader.visitMethodInsn(INVOKEVIRTUAL, eventPath, "encryptId", "(J)J", false);
		if(!cls.isPrimitive()){
			reader.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
		}
		reader.visitMethodInsn(INVOKEVIRTUAL, objectPath, id.getName(), Type.getMethodDescriptor(id), false);
	}
	private void _0(String entityPath, ASMEvent event, Class<?> cls) throws Exception {
		Method id = objectDescriptor.getMethod("setId", cls);
		MethodVisitor reader = event.writer;
		reader.visitVarInsn(ALOAD, event.setterPoint);
		reader.visitVarInsn(ALOAD, 1);
		reader.visitVarInsn(ALOAD, event.getterPoint);
		reader.visitMethodInsn(INVOKEVIRTUAL, entityPath, "getId", "()Ljava/lang/Long;");
		reader.visitMethodInsn(INVOKEVIRTUAL, eventPath, "encryptId", "(Ljava/lang/Long;)Ljava/lang/Long;");
		if(cls.isPrimitive()){
			reader.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
		}
		reader.visitMethodInsn(INVOKEVIRTUAL, objectPath, id.getName(), Type.getMethodDescriptor(id));
	}
	private PropertyReaderInitialize _0(EntityPropertyAccessor pre, Map<String, PropertyReaderInitialize> initProperties){
		EntityPropertyAccessor next = pre.getEmbeddedProperty();
		if(null == next){
			PropertyReaderInitialize rpi = initProperties.get(pre.getMappedName());
			if(null != rpi) return rpi;
			return new PropertyReaderInitializeImpl(initProperties, pre);
		}
		return _0(next, initProperties).get(pre);
	}
	/**
	 * 用于解析实体关联到的其它实体对象
	 * @param name
	 * @param objectProperty
	 * @param entityProperty
	 * @param initProperties
	 * @param event
	 * @return
	 * @throws Exception
	 */
	private boolean _parseRelatedEntity(String name, ObjectPropertyAccessor objectProperty, EntityPropertyAccessor entityProperty,
			Map<String, PropertyReaderInitialize> initProperties, ASMEvent event) throws Exception{
		if(entityProperty instanceof OnePropertyAccessor){
			PropertyReaderInitialize toPre = _0(entityProperty, initProperties);
			ReadEntityParser erp = new ReadEntityParser(this, name, objectProperty, (OnePropertyAccessor)entityProperty, toPre);
			toPre.add(erp.init());
		} else if(entityProperty instanceof ManyPropertyAccessor){
			ManyPropertyAccessor mpa = (ManyPropertyAccessor)entityProperty;
			String mappedName = entityProperty.getMappedName();
			CollctionReaderInitializeImpl toPre = _0(entityProperty, initProperties, mpa, mappedName);
			ReadCollectionParser crp = new ReadCollectionParser(this, name, objectProperty, mpa, toPre);
			toPre.add(crp.init());
		}else if(null != entityProperty){
			EntityPropertyAccessor pre = entityProperty.getEmbeddedProperty();
			if(null != pre){
				PropertyReaderInitialize toPre = _0(pre, initProperties);
				PropertyReader asmrp = _0(name, objectProperty, entityProperty, toPre);
				toPre.add(asmrp.init());
			}else{
				PropertyReader asmrp = _0(name, objectProperty, entityProperty, null);
				asmrp.init().parseProperty(event);
			}
		}else{
			return false;
		}
		return true;
	}
	private CollctionReaderInitializeImpl _0(EntityPropertyAccessor entityProperty,
			Map<String, PropertyReaderInitialize> initProperties,
			ManyPropertyAccessor mpa, String mappedName) throws Exception {
		CollctionReaderInitializeImpl toPre = (CollctionReaderInitializeImpl)initProperties.get(mappedName);
		if(null == toPre){
			EntityPropertyAccessor pre = entityProperty.getEmbeddedProperty();
			if(null != pre){
				PropertyReaderInitialize cip = _0(pre, initProperties);
				toPre = (CollctionReaderInitializeImpl)cip.get(mappedName);
				if(null == toPre){
					toPre = new CollctionReaderInitializeImpl(cip, mpa);
					cip.add(mappedName, toPre);
				}
			}else{
				toPre = new CollctionReaderInitializeImpl(null, mpa);
				initProperties.put(mappedName, toPre);
			}
		}
		return toPre;
	}
	private PropertyReader _0(String name, ObjectPropertyAccessor objectProperty, 
			EntityPropertyAccessor entityProperty, PropertyReaderInitialize toPre) throws Exception {
		ValueReader valueReader = objectProperty.getAnnotation(ValueReader.class);
		if(null != valueReader){
			return new ReadValueParser(this, name, objectProperty, entityProperty, toPre, valueReader);
		}
		Class<?> getterType = entityProperty.getType();
		Class<?> setterType = objectProperty.getType();
		if(String.class.equals(setterType)){
			if(String.class.equals(getterType)){
				Cutoff cutoff = objectProperty.getAnnotation(Cutoff.class);
				if(null != cutoff){
					//截断字符串
					ReadCutoffParser rcp = new ReadCutoffParser(cutoff);
					return new ASMReaderProperty(this, name, objectProperty, entityProperty, toPre, rcp);
				}
				Secrecy secrecy = objectProperty.getAnnotation(Secrecy.class);
				if(null != secrecy){
					Cipher cipher = objectProperty.getAnnotation(Cipher.class);
					return new ReadSecrecyParser(this, name, objectProperty, entityProperty, toPre, secrecy, cipher);
				}
			}
			FormatString formatString = objectProperty.getAnnotation(FormatString.class);
			Cipher cipher = objectProperty.getAnnotation(Cipher.class);
			if(null != formatString){
				return new ReadFormatParser(this, name, objectProperty, entityProperty, toPre, formatString, cipher);
			}
			if(null != cipher){
				return new ReadCipherParser(this, name, objectProperty, entityProperty, toPre, cipher);
			}
			if(null == stringParser) stringParser = new ReadStringParser();
			return new ASMReaderProperty(this, name, objectProperty, entityProperty, toPre, stringParser);
		}
		if(getterType.equals(setterType)){
			Cipher cipher = objectProperty.getAnnotation(Cipher.class);
			if(null != cipher){
				return new ReadCipherParser(this, name, objectProperty, entityProperty, toPre, cipher);
			}
			if(null == typeParser) typeParser = new SameParser();
			return new ASMReaderProperty(this, name, objectProperty, entityProperty, toPre, typeParser);
		}
		if(null == defaultParser){
			this.defaultParser = new PrimitiveParser().next(new ObjectParser());
		}
		return new ASMReaderProperty(this, name, objectProperty, entityProperty, toPre, defaultParser);
	}

	private PropertyParser defaultParser, typeParser, stringParser;
	private PropertyReader _0(String name, ObjectPropertyAccessor objectProperty, NameMapped entityProperty, NameMapped root) throws Exception {
		Class<?> getterType = entityProperty.entityType;
		Class<?> setterType = objectProperty.getType();
		if(String.class.equals(setterType)){
			if(String.class.equals(getterType)){
				Cutoff cutoff = objectProperty.getAnnotation(Cutoff.class);
				if(null != cutoff){
					//截断字符串
					ReadCutoffParser rcp = new ReadCutoffParser(cutoff);
					return new ASMOptimizeProperty(this, name, objectProperty, entityProperty, rcp);
				}
				Secrecy secrecy = objectProperty.getAnnotation(Secrecy.class);
				if(null != secrecy){
					Cipher cipher = objectProperty.getAnnotation(Cipher.class);
					return new OptimizeSecrecyParser(this, name, objectProperty, entityProperty, secrecy, cipher);
				}
			}
			FormatString formatString = objectProperty.getAnnotation(FormatString.class);
			Cipher cipher = objectProperty.getAnnotation(Cipher.class);
			if(null != formatString){
				AppendProperty[] properties = formatString.properties();
				int len = properties.length;
				NameMapped[] nms;
				if(len > 0){
					nms = new NameMapped[len];
					for(int i = 0; i < len; i++){
						nms[i] = root.append(entityDescriptor, properties[i].value());
					}
				}else{
					nms = null;
				}
				return new OptimizeFormatParser(this, name, objectProperty, entityProperty, formatString, nms, cipher);
			}
			if(null != cipher){
				return new OptimizeCipherParser(this, name, objectProperty, entityProperty, cipher);
			}
			if(null == stringParser) stringParser = new OptimizeStringParser();
			return new ASMOptimizeProperty(this, name, objectProperty, entityProperty, stringParser);
		}
		Cipher cipher = objectProperty.getAnnotation(Cipher.class);
		if(null != cipher && getterType.equals(setterType)){
			return new OptimizeCipherParser(this, name, objectProperty, entityProperty, cipher);
		}
		if(getterType.equals(entityProperty.dbType)){
			//这里的相同类型指的是数据库读取的类型与普通实体定义的类型相同
			if(null == typeParser) typeParser = new SameParser();
			return new ASMOptimizeProperty(this, name, objectProperty, entityProperty, typeParser);
		}
		if(null == defaultParser){
			this.defaultParser = new OptimizeObjectParser();
		}
//		if(null == defaultParser){
//			this.defaultParser = new PrimitiveParser()
//				.next(new DateParser())
//				.next(new EnumParser());
//		}
		return new ASMOptimizeProperty(this, name, objectProperty, entityProperty, defaultParser);
	}
}

/**
 * 
 * @author jackson
 *
 */
class ASMOptimizeProperty extends AbstractOptimizeProperty{
	final PropertyParser parser;
	ASMOptimizeProperty(ASMReaderBuilder builder, String name, ObjectPropertyAccessor objectProperty, 
			NameMapped entityProperty, PropertyParser parser) {
		super(builder, name, objectProperty, entityProperty);
		this.parser = parser;
	}

	@Override
	public void parseProperty(ASMEvent event) throws Exception {
		parser.parse(this, event);
	}
}

abstract class AbstractOptimizeProperty extends ASMAbstractProperty implements PropertyReader{
	final NameMapped entityProperty;
	final ASMReaderBuilder builder;
	AbstractOptimizeProperty(ASMReaderBuilder builder, String name, ObjectPropertyAccessor objectProperty, NameMapped entityProperty) {
		super(name, objectProperty, false);
		this.builder = builder;
		this.entityProperty = entityProperty;
	}

	ASMMethod omd;
	@Override
	public PropertyReader init() {
		this.getterType = entityProperty.entityType;
		this.setterType = objectProperty.getType();
		if(objectProperty.setter() == null){
			throw new RuntimeException(builder.objectPath + " setter is NULL 需补充setter");
		}
		omd = new ASMMethod(builder.objectPath, objectProperty.setter());
		return this;
	}

	@Override
	protected void loadSetter(ASMEvent event) {
		event.writer.visitVarInsn(ALOAD, event.setterPoint); 
	}

	@Override
	protected void visitSetter(MethodVisitor visitor) {
		omd.visitMethodInsn(visitor, INVOKEVIRTUAL, false);
	}

	@Override
	protected void loadGetter(ASMEvent event) {
		event.writer.visitVarInsn(ALOAD, event.getterPoint); 
	}
	
	void visitObject(MethodVisitor visitor){
		intInsn(visitor, entityProperty.ordinal);
		visitor.visitInsn(AALOAD);
	}
	
	void intInsn(MethodVisitor visitor, int ordinal){
		if(ordinal < iic.length){
			visitor.visitInsn(iic[ordinal]);
		}else{
			visitor.visitIntInsn(BIPUSH, ordinal);
		}
	}

	@Override
	protected void visitGetter(MethodVisitor visitor) {
		visitObject(visitor);
		visitor.visitTypeInsn(CHECKCAST, Type.getInternalName(entityProperty.dbType));
	}
	final int[] iic = {ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5};
}

class OptimizeFormatParser extends AbstractOptimizeProperty{
	final FormatString formatString;
	final NameMapped[] properties;
	final Cipher cipher;
	OptimizeFormatParser(ASMReaderBuilder builder, String name, ObjectPropertyAccessor objectProperty, 
			NameMapped entityProperty, FormatString formatString, NameMapped[] properties, Cipher cipher) {
		super(builder, name, objectProperty, entityProperty);
		this.cipher = cipher;
		this.formatString = formatString;
		this.properties = properties;
	}
	@Override
	public void parseProperty(ASMEvent event) throws Exception{
		MethodVisitor visitor = event.writer;
		loadSetter(event);
		if(formatString.type() == FormatValueType.FORMAT){
			visitor.visitLdcInsn(formatString.value());
		}else if(formatString.type() == FormatValueType.CONFIG){
			visitor.visitLdcInsn(builder.resolveEmbeddedValue(formatString.value()));
		}else{
			visitor.visitVarInsn(ALOAD, 1);
			visitor.visitLdcInsn(formatString.value());
			Method ffs = ReadEvent.class.getDeclaredMethod("findFormatString", String.class);
			visitor.visitMethodInsn(INVOKEVIRTUAL, builder.eventPath, ffs.getName(), Type.getMethodDescriptor(ffs), false);
		}
		if(null != properties){
			int len = properties.length + 1, il = iic.length, i = 1;
			if(len < il){
				visitor.visitInsn(iic[len]);
				il = len;
			}else{
				visitor.visitIntInsn(BIPUSH, len);
			}
			_0(event, visitor);
			for(; i < il; i++){
				visitor.visitInsn(DUP);
				visitor.visitInsn(iic[i]);
				//加字段
				_0(event, properties[i - 1]);
			}
			for(; i < len; i++){
				visitor.visitInsn(DUP);
				visitor.visitIntInsn(BIPUSH, i);
				//加字段
				_0(event, properties[i - 1]);
			}
		}else{
			visitor.visitInsn(ICONST_1);
			_0(event, visitor);
		}
		visitor.visitMethodInsn(INVOKESTATIC, "java/lang/String", "format", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;");
		visitSetter(visitor);
	}
	void _0(ASMEvent event, MethodVisitor visitor) throws Exception {
		visitor.visitTypeInsn(ANEWARRAY, "java/lang/Object");
		visitor.visitInsn(DUP);
		visitor.visitInsn(ICONST_0);
		if(null != cipher && CipherGenerator.support(setterType)){
			if(String.class.equals(setterType)){
				ASMMethod encrypt = new ASMMethod(CipherGenerator.class, "decrypt", String.class);
				visitor.visitTypeInsn(NEW, encrypt.path);  
				visitor.visitInsn(DUP);
				visitor.visitLdcInsn(cipher.value());
				visitor.visitMethodInsn(INVOKESPECIAL, encrypt.path, "<init>", "(J)V");
				loadGetter(event);
				visitGetter(visitor);
				encrypt.visitMethodInsn(visitor, INVOKEVIRTUAL, false);
			}else{
				ASMMethod encrypt = new ASMMethod(CipherGenerator.class, "decrypt", long.class);
				visitor.visitTypeInsn(NEW, encrypt.path);  
				visitor.visitInsn(DUP);
				visitor.visitLdcInsn(cipher.value());
				visitor.visitMethodInsn(INVOKESPECIAL, encrypt.path, "<init>", "(J)V");
				loadGetter(event);
				visitGetter(visitor);
				visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "longValue", "()J", false);
				encrypt.visitMethodInsn(visitor, INVOKEVIRTUAL, false);
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
			}
		}else{
			loadGetter(event);
			visitGetter(visitor);
		}
		visitor.visitInsn(AASTORE);
	}

	void _0(ASMEvent event, NameMapped nameMapped) {
		loadGetter(event);
		intInsn(event.writer, nameMapped.ordinal);
		event.visitInsn(AALOAD);
		event.visitInsn(AASTORE);
	}
	@Override
	protected void visitGetter(MethodVisitor visitor) {
		visitObject(visitor);
	}
}

class OptimizeSecrecyParser extends AbstractOptimizeProperty{
	final Cipher cipher;
	final Secrecy secrecy;
	final ASMMethod method;
	OptimizeSecrecyParser(ASMReaderBuilder builder, String name, ObjectPropertyAccessor objectProperty, 
			NameMapped entityProperty, Secrecy secrecy, Cipher cipher) throws Exception {
		super(builder, name, objectProperty, entityProperty);
		this.cipher = cipher;
		this.secrecy = secrecy;
		this.method = new ASMMethod(StringHelper.class, "secrecy", String.class, char.class, int.class, int.class);
	}
	@Override
	public void parseProperty(ASMEvent event) throws Exception {
		MethodVisitor visitor = event.writer;
		Label ifnull = new Label();
		loadGetter(event);
		visitGetter(visitor);
		visitor.visitJumpInsn(IFNULL, ifnull);
		loadSetter(event);
		if(null != cipher){
			ASMMethod encrypt = new ASMMethod(CipherGenerator.class, "decrypt", String.class);
			visitor.visitTypeInsn(NEW, encrypt.path);  
			visitor.visitInsn(DUP);
			visitor.visitLdcInsn(cipher.value());
			visitor.visitMethodInsn(INVOKESPECIAL, encrypt.path, "<init>", "(J)V");
			loadGetter(event);
			visitGetter(visitor);
			encrypt.visitMethodInsn(visitor, INVOKEVIRTUAL, false);
		}else{
			loadGetter(event);
			visitGetter(visitor);
		}
		intInsn(visitor, secrecy.value());
		intInsn(visitor, secrecy.first());
		intInsn(visitor, secrecy.last());
		method.visitMethodInsn(visitor, INVOKESTATIC, false);
		visitSetter(visitor);
		visitor.visitLabel(ifnull);
	}
}

class OptimizeCipherParser extends AbstractOptimizeProperty{
	final Cipher cipher;
	OptimizeCipherParser(ASMReaderBuilder builder, String name,
			ObjectPropertyAccessor objectProperty, NameMapped entityProperty, Cipher cipher) {
		super(builder, name, objectProperty, entityProperty);
		this.cipher = cipher;
	}
	@Override
	public void parseProperty(ASMEvent event) throws Exception {
		MethodVisitor reader = event.writer;
		loadSetter(event);
		if(CipherGenerator.support(getterType)){
			if(String.class.equals(getterType)){
				ASMMethod encrypt = new ASMMethod(CipherGenerator.class, "decrypt", String.class);
				reader.visitTypeInsn(NEW, encrypt.path);  
				reader.visitInsn(DUP);
				reader.visitLdcInsn(cipher.value());
				reader.visitMethodInsn(INVOKESPECIAL, encrypt.path, "<init>", "(J)V", false);
				loadGetter(event);
				visitGetter(reader);
				encrypt.visitMethodInsn(reader, INVOKEVIRTUAL, false);
			}else{
				ASMMethod encrypt = new ASMMethod(CipherGenerator.class, "decrypt", long.class);
				reader.visitTypeInsn(NEW, encrypt.path);  
				reader.visitInsn(DUP);
				reader.visitLdcInsn(cipher.value());
				reader.visitMethodInsn(INVOKESPECIAL, encrypt.path, "<init>", "(J)V", false);
				loadGetter(event);
				visitGetter(reader);
				reader.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "longValue", "()J", false);
				encrypt.visitMethodInsn(reader, INVOKEVIRTUAL, false);
				if(int.class.equals(setterType)){
					reader.visitInsn(L2I);
				}else if(Integer.class.equals(setterType)){
					reader.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(J)Ljava/lang/Long;", false);
				}else if(Long.class.equals(setterType)){
					reader.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
				}
			}
		}else{
			loadGetter(event);
			visitGetter(reader);
		}
		visitSetter(reader);
	}
}

class OptimizeStringParser extends AbstractStringParser{
	@Override
	public void parse(ASMAbstractProperty property, ASMEvent event) throws Exception {
		// TODO 把其它类型转为字符串
		MethodVisitor visitor = event.writer;
		ASMOptimizeProperty asmop = (ASMOptimizeProperty)property;
		NameMapped nameMapped = asmop.entityProperty;
		Class<?> dbt = nameMapped.dbType;
		/*
		 * 1.日期类型转为字符串
		 * 2.基本数据类型转为字符串
		 * 3.其它类型的对象转字符串
		 */
		if(Date.class.equals(dbt)){
			Temporal temporal = nameMapped.propertyAccessor.getAnnotation(Temporal.class);
			String fs;
			if(null == temporal || temporal.value() == TemporalType.DATE){
				fs = "date2String";
			}else if(temporal.value() == TemporalType.TIMESTAMP){
				fs = "datetime2String";
			}else{
				fs = "time2String";
			}
			ASMMethod toString = new ASMMethod(StringHelper.class, fs, Date.class);
			property.loadSetter(event);
			property.loadGetter(event);
			property.visitGetter(visitor);
			toString.visitMethodInsn(visitor, INVOKESTATIC, false);
			property.visitSetter(visitor);
		}else{ 
			ASMReaderBuilder builder = asmop.builder;
			if(Number.class.isAssignableFrom(dbt)){
				OptionArrayParser oap = _parseOptionArray(builder, asmop, asmop.iic);
				if(null != oap){
					Label ifnull = new Label();
					property.loadGetter(event);
					property.visitGetter(visitor);
					visitor.visitJumpInsn(IFNULL, ifnull);
					property.loadSetter(event);
					oap.getArray(visitor);
					property.loadGetter(event);
					property.visitGetter(visitor);
					visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I", false);
					oap.getOffset(visitor);
					visitor.visitInsn(ISUB);
					visitor.visitInsn(AALOAD);
					property.visitSetter(visitor);
					visitor.visitLabel(ifnull);
					return;//结束
				}
			}else if(dbt.isEnum()){
				OptionArrayParser oap = _parseOptionArray(builder, asmop, asmop.iic);
				if(null != oap){
					String des = Type.getInternalName(dbt);
					Label ifnull = new Label();
					property.loadGetter(event);
					property.visitGetter(visitor);
					visitor.visitJumpInsn(IFNULL, ifnull);
					property.loadSetter(event);
					oap.getArray(visitor);
					property.loadGetter(event);
					property.visitGetter(visitor);
					visitor.visitMethodInsn(INVOKEVIRTUAL, des, "ordinal", "()I", false);
					oap.getOffset(visitor);
					visitor.visitInsn(ISUB);
					visitor.visitInsn(AALOAD);
					property.visitSetter(visitor);
					visitor.visitLabel(ifnull);
					return;//结束
				}
				//TODO 这里是从数据库直接转为对应的枚举类型，从数据库读出来的值应该是int或string类型
				//所以上面的操作可能会出错的
			}else if(Boolean.class.equals(dbt)){
				OptionArrayParser oap = _parseOptionArray(builder, asmop, asmop.iic);
				if(null != oap){
					Label ifnull = new Label();
					property.loadGetter(event);
					property.visitGetter(visitor);
					visitor.visitJumpInsn(IFNULL, ifnull);
					property.loadSetter(event);
					oap.getArray(visitor);
					property.loadGetter(event);
					property.visitGetter(visitor);
					visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
					oap.getOffset(visitor);
					visitor.visitInsn(ISUB);
					visitor.visitInsn(AALOAD);
					property.visitSetter(visitor);
					visitor.visitLabel(ifnull);
					return;//结束
				}
			}
			Label ifnull = new Label();
			asmop.loadGetter(event);
			asmop.visitObject(visitor);
			visitor.visitJumpInsn(IFNULL, ifnull);
			asmop.loadSetter(event);
			asmop.loadGetter(event);
			asmop.visitGetter(visitor);
			visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(dbt), "toString", "()Ljava/lang/String;", false);
			asmop.visitSetter(visitor);
			visitor.visitLabel(ifnull);
		}
	}
}

class OptimizeObjectParser implements PropertyParser{

	@Override
	public void parse(ASMAbstractProperty property, ASMEvent event) throws Exception {
		// TODO OptimizeObjectParser
		Class<?> st = property.setterType;
		ASMOptimizeProperty asmop = (ASMOptimizeProperty)property;
		NameMapped nameMapped = asmop.entityProperty;
		Class<?> dbt = nameMapped.dbType;
		MethodVisitor reader = event.writer;
		if(Integer.class.equals(st)){
			property.loadSetter(event);
			property.loadGetter(event);
			property.visitGetter(reader);
			if(dbt.isEnum()){
				reader.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(dbt), "ordinal", "()I", false);
			}else{
				_0(reader, dbt, Integer.class, "intValue", ICONST_0, ICONST_1);
			}
			reader.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
			property.visitSetter(event.writer);
		}else if(Long.class.equals(st)){
			if(Date.class.equals(dbt)){
				Label ifnull = new Label();
				asmop.loadGetter(event);
				asmop.visitObject(reader);
				reader.visitJumpInsn(IFNULL, ifnull);
				reader.visitMethodInsn(INVOKEVIRTUAL, "java/util/Date", "getTime", "()J", false);
				reader.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
				property.visitSetter(event.writer);
				reader.visitLabel(ifnull);
			}else{
				property.loadSetter(event);
				property.loadGetter(event);
				property.visitGetter(reader);
				_0(reader, dbt, Long.class, "longValue", ICONST_0, ICONST_1);
				reader.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
				property.visitSetter(event.writer);
			}
		}else if(Double.class.equals(st)){
			property.loadSetter(event);
			property.loadGetter(event);
			property.visitGetter(reader);
			_0(reader, dbt, Double.class, "doubleValue", ICONST_0, ICONST_1);
			reader.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(J)Ljava/lang/Double;", false);
			property.visitSetter(event.writer);
		}else if(Float.class.equals(st)){
			property.loadSetter(event);
			property.loadGetter(event);
			property.visitGetter(reader);
			_0(reader, dbt, Float.class, "floatValue", ICONST_0, ICONST_1);
			reader.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(J)Ljava/lang/Float;", false);
			property.visitSetter(event.writer);
		}else if(Boolean.class.equals(st)){
			property.loadSetter(event);
			property.loadGetter(event);
			property.visitGetter(reader);
			if(!$other_boolean(property, event, st)){
				//直接调用对象的toString方法来解析boolean值
				reader.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(st), "toString", "()Ljava/lang/String;", false);
				reader.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Ljava/lang/String;)Ljava/lang/Boolean;", false);
			}
			property.visitSetter(event.writer);
		}else if(st.isPrimitive()){
			property.loadSetter(event);
			property.loadGetter(event);
			property.visitGetter(reader);
			if(boolean.class.equals(st)){
				if(Boolean.class.equals(dbt)){
					reader.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
				}else if(!$other_boolean(property, event, dbt)){
					//直接调用对象的toString方法来解析boolean值
					reader.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(dbt), "toString", "()Ljava/lang/String;", false);
					reader.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Ljava/lang/String;)Ljava/lang/Boolean;", false);
					reader.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
				}
			}else if(long.class.equals(st)){
				if(Date.class.equals(dbt)){
					reader.visitMethodInsn(INVOKEVIRTUAL, "java/util/Date", "getTime", "()J", false);
				}else if(Character.class.equals(dbt)){
					reader.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
					reader.visitInsn(I2L);
				}else{
					_0(reader, dbt, Long.class, "longValue", LCONST_0, LCONST_1);
				}
			}else if(double.class.equals(st)){
				if(Character.class.equals(dbt)){
					reader.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
					reader.visitInsn(I2D);
				}else{
					_0(reader, dbt, Double.class, "doubleValue", DCONST_0, DCONST_1);
				}
			}else if(float.class.equals(st)){
				if(Character.class.equals(dbt)){
					reader.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
					reader.visitInsn(I2F);
				}else{
					_0(reader, dbt, Float.class, "floatValue", FCONST_0, FCONST_1);
				}
			}else{
				if(dbt.isEnum()){
					reader.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(dbt), "ordinal", "()I", false);
				}else if(Character.class.equals(dbt)){
					reader.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
				}else{
					_0(reader, dbt, Integer.class, "intValue", ICONST_0, ICONST_1);
				}
			}
			property.visitSetter(reader);
		}else if(st.isEnum()){
			if(Number.class.equals(dbt)){
				ASMMethod values = new ASMMethod(st, "values");
				asmop.loadSetter(event);
				values.visitMethodInsn(reader, INVOKESTATIC, false);
				asmop.loadGetter(event);
				asmop.visitGetter(reader);
				reader.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I", false);
				reader.visitInsn(AALOAD);
				asmop.visitSetter(reader);
			}else if(String.class.equals(dbt)){
				ASMMethod valueOf = new ASMMethod(st, "valueOf", String.class);
				asmop.loadSetter(event);
				asmop.loadGetter(event);
				asmop.visitGetter(reader);
				valueOf.visitMethodInsn(reader, INVOKESTATIC, false);
				reader.visitInsn(AALOAD);
				asmop.visitSetter(reader);
			}
		}else if(Date.class.equals(st)){
			if(String.class.equals(dbt)){
				//格式化处理，都格式化成日期+时间类型，存和取的时候再根据具体的情况来处理
				ASMMethod toDatetime = new ASMMethod(StringHelper.class, "toDatetime", String.class);
				property.loadSetter(event);
				property.loadGetter(event);
				property.visitGetter(reader);
				toDatetime.visitMethodInsn(reader, INVOKESTATIC, false);
				property.visitSetter(reader);
			}else if(Number.class.isAssignableFrom(dbt)){
				Label ifnull = new Label();
				asmop.loadGetter(event);
				asmop.visitObject(reader);
				reader.visitJumpInsn(IFNULL, ifnull);
				asmop.loadSetter(event);
				reader.visitTypeInsn(NEW, "java/util/Date");  
				reader.visitInsn(DUP);
				asmop.loadGetter(event);
				asmop.visitGetter(reader);
				reader.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(dbt), "longValue", "()J", false);
				reader.visitMethodInsn(INVOKESPECIAL, "java/util/Date", "<init>", "(J)V", false);
				asmop.visitSetter(reader);
				reader.visitLabel(ifnull);
			}
		}else if(Character.class.equals(st)){
			property.loadSetter(event);
			property.loadGetter(event);
			property.visitGetter(reader);
			_0(reader, dbt, Integer.class, "intValue", ICONST_0, ICONST_1);
			reader.visitInsn(I2C);
			reader.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
			property.visitSetter(reader);
		}else if(Short.class.equals(st)){
			property.loadSetter(event);
			property.loadGetter(event);
			property.visitGetter(reader);
			_0(reader, dbt, Integer.class, "intValue", ICONST_0, ICONST_1);
			reader.visitInsn(I2S);
			reader.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
			property.visitSetter(reader);
		}else if(Byte.class.equals(st)){
			property.loadSetter(event);
			property.loadGetter(event);
			property.visitGetter(reader);
			_0(reader, dbt, Integer.class, "intValue", ICONST_0, ICONST_1);
			reader.visitInsn(I2B);
			reader.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
			property.visitSetter(reader);
		}
		ObjectClass oc = property.objectProperty.getAnnotation(ObjectClass.class);
		Class<?> tryClass = null == oc ? st : oc.value();
		try{
			Constructor<?> con = tryClass.getConstructor(dbt);
			String tcDes = Type.getInternalName(tryClass);
			property.loadSetter(event);
			reader.visitTypeInsn(NEW, tcDes);  
			reader.visitInsn(DUP);
			property.loadGetter(event);
			property.visitGetter(reader);
			reader.visitMethodInsn(INVOKESPECIAL, tcDes, "<init>", Type.getConstructorDescriptor(con));
			property.visitSetter(reader);
		}catch(Exception t){ /*nothing to do!*/ }
	}
	
	void _0(MethodVisitor visitor, Class<?> to, Class<?> numClass, String name, int const_0, int const_1) throws Exception {
		if(Number.class.isAssignableFrom(to)){
			String des = Type.getMethodDescriptor(to.getDeclaredMethod(name));
			visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(to), name, des, false);
		}else if(Boolean.class.equals(to)){
			visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
			$boolean_primitive(visitor, IFEQ, const_0, const_1);
		}else{
			String classPath = Type.getInternalName(numClass);
			String valdes = Type.getMethodDescriptor(numClass.getDeclaredMethod(name));
			String ofdes = Type.getMethodDescriptor(numClass.getDeclaredMethod("valueOf", String.class));
			visitor.visitMethodInsn(INVOKESTATIC, classPath, "valueOf", ofdes);
			visitor.visitMethodInsn(INVOKEVIRTUAL, classPath, name, valdes, false);
		}
	}
	
	void $boolean_primitive(MethodVisitor visitor, int jump_if, int const_0, int const_1){
		Label ifeq = new Label();
		Label ifelse = new Label();
		visitor.visitJumpInsn(jump_if, ifeq);
		visitor.visitInsn(const_1);
		visitor.visitJumpInsn(GOTO, ifelse);
		visitor.visitLabel(ifeq);
		visitor.visitInsn(const_0);
		visitor.visitLabel(ifelse);
	}
	
	boolean $other_boolean(ASMAbstractProperty property, ASMEvent event, Class<?> to){
		MethodVisitor visitor = event.writer;
		if(Number.class.isAssignableFrom(to)){
			visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(to), "intValue", "()I", false);
			visitor.visitInsn(ICONST_1);
			$boolean_primitive(visitor, IF_ICMPNE, ICONST_0, ICONST_1);
		}else if(Character.class.equals(to)){
			Label ifeq = new Label();
			Label ifelse = new Label();
			visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
			visitor.visitIntInsn(BIPUSH, 49);
			visitor.visitJumpInsn(IF_ICMPEQ, ifeq);
			property.loadGetter(event);
			property.visitGetter(visitor);
			visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
			visitor.visitIntInsn(BIPUSH, 84);
			visitor.visitJumpInsn(IF_ICMPEQ, ifeq);
			property.loadGetter(event);
			property.visitGetter(visitor);
			visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
			visitor.visitIntInsn(BIPUSH, 116);
			visitor.visitJumpInsn(IF_ICMPEQ, ifeq);
			visitor.visitInsn(ICONST_0);
			visitor.visitJumpInsn(GOTO, ifelse);
			visitor.visitLabel(ifeq);
			visitor.visitInsn(ICONST_1);
			visitor.visitLabel(ifelse);
		}else{
			return false;
		}
		return true;
	}
}

/**
 * <pre>
 * 实体的多个字段从数据库表的同一个字段读取值的情况
 * 从数据库读出来的是一个对象数组，所以这里不会是基本类型
 * </pre>
 * @author jackson
 *
 */
class NameMapped{
	final int ordinal;
	final String name;
	final Class<?> entityType, dbType;
	NameMapped next;
	EntityPropertyAccessor propertyAccessor;
	NameMapped(){
		this.name = "id";
		this.ordinal = 0;
		this.entityType = Long.class;
		this.dbType = Number.class;
	}
	private NameMapped(int ordinal, String name, Class<?> entityType, Class<?> dbType){
		this.name = name;
		this.ordinal = ordinal;
		this.dbType = dbType;
		this.entityType = entityType;
	}
	NameMapped append(EntityDescriptor entityDescriptor, String name){
		if(this.name.equals(name)){
			return this;
		}
		if(null != next){
			return next.append(entityDescriptor, name);
		}
		EntityPropertyAccessor epa = entityDescriptor.get(name);
		if(null == epa){
			if(name.indexOf('[') >= 0){
				return null;
			}
			String[] names = name.split("\\.");
			int len = names.length;
			if(len <= 1){
				return null;
			}
			String mappedname = names[0];
			EntityPropertyAccessor pre = entityDescriptor.get(mappedname);
			if(null == pre){
				return null;//第一个节点不能为空
			}
			EntityDescriptor ted = entityDescriptor;
			for(int i = 1; i < len; i++){
				mappedname += '.' + names[i];
				epa = ted.get(mappedname);
				if(null == epa){
					mappedname = names[i];
					ted = DescriptorFactory.entityDescriptor(pre.getType());
					epa = ted.get(mappedname);
					if(null == epa){
						return null;
					}
				}
				pre = epa;
			}
		}
		Class<?> type, dbType;
		//如果是关联关系的情况，一对多、多对多
//		if(epa instanceof OnePropertyAccessor){
//			
//		} else if(epa instanceof ManyPropertyAccessor){
//			
//		}else{
			type = epa.getType();
			if(type.isPrimitive()){
				if(char.class.equals(type)){
					dbType = Character.class;
				}else if(boolean.class.equals(type)){
					dbType = Boolean.class;
				}else{
					dbType = Number.class;
				}
			}else{
				dbType = type;
			}
			
//		}
		next = new NameMapped(ordinal + 1, name, type, dbType);
		next.propertyAccessor = epa;
		return next;
	}
	void toString(StringBuilder sb){
		sb.append(" x.").append(name);
		if(null != next){
			next.toString(sb.append(','));
		}
	}
}

interface PropertyReaderInitialize extends ASMProperty{

	void add(ASMProperty property);

	void add(String mappedName, PropertyReaderInitialize curr);

	Class<?> getType();

	PropertyReaderInitialize get(Object key);

	void loadGetter(ASMEvent event);

	PropertyReaderInitialize get(EntityPropertyAccessor pre);
	
}

@SuppressWarnings("serial")
class PropertyReaderInitializeImpl extends AbstractPropertyReaderInitialize<EntityPropertyAccessor> {

	PropertyReaderInitializeImpl(PropertyReaderInitialize toPre, EntityPropertyAccessor accessor) {
		super(toPre, accessor);
	}
	PropertyReaderInitializeImpl(Map<String, PropertyReaderInitialize> initProperties, EntityPropertyAccessor accessor) {
		super(null, accessor);
		initProperties.put(accessor.getMappedName(), this);
	}

	@Override
	public PropertyReaderInitialize get(EntityPropertyAccessor key) {
		PropertyReaderInitialize rpi = get(key.getMappedName());
		if(null == rpi){
			rpi = new PropertyReaderInitializeImpl((PropertyReaderInitialize)this, key);
			put(key.getMappedName(), rpi);
		}
		return rpi;
	}
}
@SuppressWarnings("serial")
abstract class AbstractPropertyReaderInitialize<EPA extends EntityPropertyAccessor> 
	extends HashMap<String, PropertyReaderInitialize> implements PropertyReaderInitialize{

	final List<ASMProperty> properties;
	final ASMMethod mappedGetter;
	final PropertyReaderInitialize toPre;
	final EPA accessor;
	
	@Override
	public Class<?> getType() {
		return accessor.getType();
	}
	
	AbstractPropertyReaderInitialize(PropertyReaderInitialize toPre, EPA accessor){
		super(2);
		this.properties = new ArrayList<ASMProperty>();
		this.accessor = accessor;
		this.toPre = toPre;
		this.mappedGetter = new ASMMethod(accessor.getOwnerClass(), accessor.getter());
	}
	
	@Override
	public void parseProperty(ASMEvent event) throws Exception {
		Label ifnull = new Label();
		event.writer.visitVarInsn(ALOAD, event.getterPoint); 
		loadGetter(event);
		event.writer.visitJumpInsn(IFNULL, ifnull);
		for(ASMProperty ap : properties){
			ap.parseProperty(event);
		}
		for(PropertyReaderInitialize ap : values()){
			ap.parseProperty(event);
		}
		event.writer.visitLabel(ifnull);
	}
	
	@Override
	public void loadGetter(ASMEvent event) {
		if(null != toPre) toPre.loadGetter(event);
		mappedGetter.visitMethodInsn(event.writer, INVOKEVIRTUAL, false);
	}
	
	@Override
	public void add(ASMProperty property) {
		properties.add(property);
	}
	
	@Override
	public void add(String mappedName, PropertyReaderInitialize curr) {
		put(mappedName, curr);
	}
}

class ASMReaderProperty extends AbstractReaderProperty{
	ASMReaderProperty(ASMReaderBuilder asmBuilder, String name,
			ObjectPropertyAccessor objectProperty,
			EntityPropertyAccessor entityProperty, PropertyReaderInitialize toPre, PropertyParser internalParser) {
		super(asmBuilder, name, objectProperty, entityProperty, toPre);
		this.internalParser = internalParser;
	}
	final PropertyParser internalParser;
	
	public void parseProperty(ASMEvent event) throws Exception{
		internalParser.parse(this, event);
	}
}

interface PropertyReader extends ASMProperty{
	PropertyReader init();
}

abstract class AbstractReaderProperty extends ASMAbstractProperty implements PropertyReader{
	final ASMReaderBuilder builder;
	EntityPropertyAccessor entityProperty;
	ASMMethod omd;
	PropertyReaderInitialize toPre;
	ASMMethod mappedProperty;
	
	AbstractReaderProperty(ASMReaderBuilder asmBuilder, String name, ObjectPropertyAccessor objectProperty) {
		super(name, objectProperty, false);
		this.builder = asmBuilder;
	}
	
	AbstractReaderProperty(ASMReaderBuilder asmBuilder, String name, ObjectPropertyAccessor objectProperty, 
			EntityPropertyAccessor entityProperty, PropertyReaderInitialize toPre) {
		this(asmBuilder, name, objectProperty);
		this.entityProperty = entityProperty;
		this.toPre = toPre;
	}
	
	@Override
	protected void visitGetter(MethodVisitor visitor) {
		mappedProperty.visitMethodInsn(visitor, INVOKEVIRTUAL, false);
	}
	
	@Override
	public PropertyReader init(){
		mappedProperty = new ASMMethod(Type.getInternalName(entityProperty.getOwnerClass()), entityProperty.getter());
		setterType = objectProperty.getType();
		getterType = entityProperty.getType();
		omd = new ASMMethod(builder.objectPath, objectProperty.setter());
		return this;
	}

	@Override
	protected void loadSetter(ASMEvent event) {
		event.writer.visitVarInsn(ALOAD, event.setterPoint); 
	}

	@Override
	protected void loadGetter(ASMEvent event) {
		event.writer.visitVarInsn(ALOAD, event.getterPoint); 
		if(null != toPre) toPre.loadGetter(event);
	}

	@Override
	protected void visitSetter(MethodVisitor visitor) {
		omd.visitMethodInsn(visitor, INVOKEVIRTUAL, false);
	}
	
}

/**
 * 如果普通实体的字段名或定义的名称指向的是一个实体，则只能处理Long,long和String三种类型的数据
 * @author jackson
 *
 */
class ReadEntityParser extends AbstractReaderProperty{
	ReadEntityParser(ASMReaderBuilder asmBuilder, String name, ObjectPropertyAccessor objectProperty,
			OnePropertyAccessor entityProperty, PropertyReaderInitialize toPre) {
		super(asmBuilder, name, objectProperty, entityProperty, toPre);
	}
	
	@Override
	public void parseProperty(ASMEvent event) throws Exception {
		if(Long.class.equals(setterType)){
			loadSetter(event);
			loadGetter(event);
			event.writer.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(getterType), "getId", "()Ljava/lang/Long;", false);
			visitSetter(event.writer);
		}else if(String.class.equals(setterType)){
			loadSetter(event);
			loadGetter(event);
			if(AbstractEntity.class.isAssignableFrom(getterType)){
				event.writer.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(getterType), "getName", "()Ljava/lang/String;");
			}else{
				event.writer.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(getterType), "getId", "()Ljava/lang/Long;");
				event.writer.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "toString", "()Ljava/lang/String;");
			}
			visitSetter(event.writer);
		}else if(long.class.equals(setterType)){
			loadSetter(event);
			loadGetter(event);
			event.writer.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(getterType), "getId", "()Ljava/lang/Long;");
			event.writer.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
			visitSetter(event.writer);
		}
	}

	@Override
	public PropertyReader init() {
		setterType = objectProperty.getType();
		getterType = entityProperty.getType();
		omd = new ASMMethod(builder.objectPath, objectProperty.setter());
		return this;
	}
}

@SuppressWarnings("serial")
class CollctionReaderInitializeImpl extends AbstractPropertyReaderInitialize<ManyPropertyAccessor>{
	final int invoke;
	final String typeDes;
	final EntityDescriptor entityDescriptor;
	final boolean isBase;
	
	CollctionReaderInitializeImpl(PropertyReaderInitialize toPre, ManyPropertyAccessor accessor) throws Exception {
		super(toPre, accessor);
		if(accessor.isInterface()){
			invoke = INVOKEINTERFACE;
		}else{
			invoke = INVOKEVIRTUAL;
		}
		Class<?> entityActualType = accessor.getActualType();
		this.entityDescriptor = DescriptorFactory.entityDescriptor(entityActualType);
		this.isBase = AbstractEntity.class.isAssignableFrom(entityActualType);
		this.typeDes = Type.getInternalName(entityActualType);
	}

	@Override
	public PropertyReaderInitialize get(EntityPropertyAccessor pre) {
		throw new RuntimeException();
	}

	@Override
	public void parseProperty(ASMEvent event) throws Exception {
		Method empty = accessor.emptyMethod();
		CollectionEvent collectionEvent = new CollectionEvent(event, accessor);
		event.writer.visitVarInsn(ALOAD, event.getterPoint); 
		loadGetter(event);
		event.writer.visitVarInsn(ASTORE, collectionEvent.collPoint);
		event.writer.visitVarInsn(ALOAD, collectionEvent.collPoint);
		event.writer.visitJumpInsn(IFNULL, collectionEvent.ifnull);
		event.writer.visitVarInsn(ALOAD, collectionEvent.collPoint);
		event.writer.visitMethodInsn(invoke, collectionEvent.des, empty.getName(), Type.getMethodDescriptor(empty));
		event.writer.visitJumpInsn(IFNE, collectionEvent.ifnull);
		event.writer.visitVarInsn(ALOAD, collectionEvent.collPoint);
		event.writer.visitMethodInsn(invoke, collectionEvent.des, "size", "()I");
		event.writer.visitVarInsn(ISTORE, collectionEvent.indexPoint);

		for(ASMProperty ap : properties){
			((CollectionPropertyParser)ap).init(collectionEvent);
		}

		event.writer.visitInsn(ICONST_0);
		event.writer.visitVarInsn(ISTORE, collectionEvent.indexPoint);
		event.writer.visitVarInsn(ALOAD, collectionEvent.collPoint);
		event.writer.visitMethodInsn(invoke, collectionEvent.des, "iterator", "()Ljava/util/Iterator;");
		event.writer.visitVarInsn(ASTORE, collectionEvent.iterPoint);
		event.writer.visitJumpInsn(GOTO, collectionEvent.start);
		event.writer.visitLabel(collectionEvent.loop);
		event.writer.visitVarInsn(ALOAD, collectionEvent.iterPoint);
		event.writer.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;");
		event.writer.visitTypeInsn(CHECKCAST, typeDes);
		event.writer.visitVarInsn(ASTORE, collectionEvent.itemPoint);
		for(ASMProperty ap : properties){
			((CollectionPropertyParser)ap).parseProperty(event);
		}

		event.writer.visitIincInsn(collectionEvent.indexPoint, 1);
		event.writer.visitLabel(collectionEvent.start);
		event.writer.visitVarInsn(ALOAD, collectionEvent.iterPoint);
		event.writer.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z");
		event.writer.visitJumpInsn(IFNE, collectionEvent.loop);
		for(ASMProperty ap : properties){
			((CollectionPropertyParser)ap).finish();
		}
		event.writer.visitLabel(collectionEvent.ifnull);
	}
}

class CollectionEvent{
	final ASMEvent event;
	final MethodVisitor visitor;
	final int collPoint, iterPoint, itemPoint, indexPoint;
	final String des/*, typeDes*/;
	final Label ifnull = new Label(), start = new Label(), loop = new Label();
	CollectionEvent(ASMEvent event, ManyPropertyAccessor accessor){
		this.event = event;
		this.collPoint = event.assignPoint();
		this.iterPoint = event.assignPoint();
		this.itemPoint = event.assignPoint();
		this.indexPoint = event.assignPoint();
		this.visitor = event.writer;
		this.des = Type.getInternalName(accessor.getType());
	}
}

interface CollectionPropertyParser extends ASMProperty{
	void init(CollectionEvent event);
	void finish();
}

class ReadCollectionParser extends AbstractReaderProperty implements CollectionPropertyParser{
	final ManyPropertyAccessor manyPropertyAccessor;
	final CollctionReaderInitializeImpl collctionReaderInitializeImpl;
	ReadCollectionParser(ASMReaderBuilder asmBuilder, String name, String subname, ObjectPropertyAccessor objectProperty,
			ManyPropertyAccessor manyPropertyAccessor, CollctionReaderInitializeImpl toPre) throws Exception {
		super(asmBuilder, name, objectProperty);
		this.manyPropertyAccessor = manyPropertyAccessor;
		this.collctionReaderInitializeImpl = toPre;
		this.typeDes = collctionReaderInitializeImpl.typeDes;
		this.isBase = collctionReaderInitializeImpl.isBase;
		this.subname = subname;
	}
	ReadCollectionParser(ASMReaderBuilder asmBuilder, String name, ObjectPropertyAccessor objectProperty,
			ManyPropertyAccessor manyPropertyAccessor, CollctionReaderInitializeImpl toPre) throws Exception {
		this(asmBuilder, name, null, objectProperty, manyPropertyAccessor, toPre);
	}
	final String subname, typeDes;
	final boolean isBase;
	ASMMethod convert;
	CollectionPropertyParser collectionParser;
	@Override
	public PropertyReader init() {
		setterType = objectProperty.getType();
		omd = new ASMMethod(builder.objectPath, objectProperty.setter());
		EntityDescriptor entityDescriptor = collctionReaderInitializeImpl.entityDescriptor;
		Class<?> to = objectProperty.getType();
		if(null != subname){
			entityProperty = entityDescriptor.get(subname);
			if(null != entityProperty){
				getterType = entityProperty.getType();
				mappedProperty = new ASMMethod(typeDes, entityProperty.getter());
				if(Collection.class.isAssignableFrom(to)){
					Class<?> toType = objectProperty.getActualType();
					if(toType.isAssignableFrom(getterType)){
						collectionParser = new CollectionParser(to);
					}else{
						try{
							collectionParser = new CollectionFieldParser(to, _0(toType));
						}catch(Exception t){ /*ignore*/ }
					}
				}else if(to.isArray()){
					Class<?> toType = to.getComponentType();
					if(toType.isAssignableFrom(getterType)){
						collectionParser = new ArrayParser(toType);
					}else{
						try{
							collectionParser = new ArrayFieldParser(_0(toType));
						}catch(Exception t){ /*ignore*/ }
					}
				}else if(String.class.equals(to)){
					convert = new ASMMethod(typeDes, "toString", "()Ljava/lang/String;");
					collectionParser = new ObjectStringParser();
				}
			}
		}else{
			if(Collection.class.isAssignableFrom(to)){
				Class<?> toType = objectProperty.getActualType();
				getterType = manyPropertyAccessor.getActualType();
				if(toType.isAssignableFrom(getterType)){
					collectionParser = new CollectionParser(to);
				}else if(Long.class.equals(toType)){
					_0();
					collectionParser = new CollectionParser(to);
				}else if(String.class.equals(toType)){
					_2();
					collectionParser = new CollectionParser(to);
				}else{
					try{
						collectionParser = new CollectionObjectParser(to, _0(toType));
					}catch(Exception t){ /*ignore*/ }
				}
			}else if(to.isArray()){//TODO
				Class<?> toType = to.getComponentType();
				if(long.class.equals(toType)){
					_0();
					collectionParser = new ArrayLongParser();
				}else if(Long.class.equals(toType)){
					_0();
					collectionParser = new ArrayParser(toType);
				}else if(String.class.equals(toType)){
					_2();
					collectionParser = new ArrayParser(toType);
				}else{
					try{
						collectionParser = new ArrayObjectParser(_0(toType));
					}catch(Exception t){ /*ignore*/ }
				}
			}else if(String.class.equals(to)){
				_2();
				collectionParser = new ObjectStringParser();
			}else{
				try{
					collectionParser = new ObjectOtherParser(_0(to));
				}catch(Exception t){ /*ignore*/ }
			}
			
		}
		if(collectionParser == null) collectionParser = new CollectionPropertyParser(){
			@Override
			public void parseProperty(ASMEvent event) throws Exception { }
			@Override
			public void init(CollectionEvent event) { }
			@Override
			public void finish() { }
		};
		return this;
	}
	Class<?> _0(Class<?> toType){
		ObjectClass objectClass = objectProperty.getAnnotation(ObjectClass.class);
		return null == objectClass ? toType : objectClass.value();
	}
	void _0(){
		getterType = Long.class;
		mappedProperty = new ASMMethod(typeDes, "getId", "()Ljava/lang/Long;");
	}
	void _1(){
		getterType = String.class;
		mappedProperty = new ASMMethod(typeDes, "getName", "()Ljava/lang/String;");
	}
	void _2() {
		if(isBase){
			_1();
		}else{
			_0();
			convert = new ASMMethod("java/lang/Long", "toString", "()Ljava/lang/String;");
		}
	}
	int point = 0;
	@Override
	public void init(CollectionEvent event) {
		collectionEvent = event;
		collectionParser.init(event);
	}
	
	@Override
	public void finish() {
		collectionParser.finish();
	}
	
	@Override
	public void parseProperty(ASMEvent event) throws Exception {
		collectionParser.parseProperty(event);
	}
	CollectionEvent collectionEvent;
	abstract class AbstractArrayParser implements CollectionPropertyParser{

		@Override
		public void init(CollectionEvent event) {
			point = event.event.assignPoint();
			event.visitor.visitVarInsn(ASTORE, point);
		}

		@Override
		public final void finish() {
			loadSetter(collectionEvent.event);
			collectionEvent.visitor.visitVarInsn(ALOAD, point);
			visitSetter(collectionEvent.visitor);
		}
	}
	class ArrayLongParser extends AbstractArrayParser{

		@Override
		public void parseProperty(ASMEvent event) throws Exception {
			event.writer.visitVarInsn(ALOAD, point);
			event.writer.visitVarInsn(ILOAD, collectionEvent.indexPoint);
			loadGetter(event);
			visitGetter(event.writer);
			event.writer.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
			event.writer.visitInsn(LASTORE);
		}

		@Override
		public void init(CollectionEvent event) {
			event.visitor.visitVarInsn(ILOAD, event.indexPoint);
			event.visitor.visitIntInsn(NEWARRAY, T_LONG);
			super.init(event);
		}
		
	}
	abstract class AbstractCollectionParser implements CollectionPropertyParser{
		AbstractCollectionParser(Class<?> clsc){
			if(clsc.isInterface()){
				if(Set.class.equals(clsc)){
					clsName = "java/util/HashSet";
				}else{
					clsName = "java/util/ArrayList";
				}
			}else{
				clsName = Type.getInternalName(clsc);
			}
		}
		final String clsName;
		@Override
		public void init(CollectionEvent event) {
			event.visitor.visitTypeInsn(NEW, clsName);
			event.visitor.visitInsn(DUP);
			event.visitor.visitMethodInsn(INVOKESPECIAL, clsName, "<init>", "()V");
			point = event.event.assignPoint();
			event.visitor.visitVarInsn(ASTORE, point);
		}
		
		@Override
		public final void finish() {
			loadSetter(collectionEvent.event);
			collectionEvent.visitor.visitVarInsn(ALOAD, point);
			visitSetter(collectionEvent.visitor);
		}
	}
	class CollectionObjectParser extends AbstractCollectionParser{
		final String objectDes;
		final Constructor<?> constructor;
		CollectionObjectParser(Class<?> collectionType, Class<?> genericsType) throws Exception {
			super(collectionType);
			constructor = genericsType.getDeclaredConstructor(manyPropertyAccessor.getActualType());
			objectDes = Type.getInternalName(genericsType);
		}
		@Override
		public void parseProperty(ASMEvent event) throws Exception {
			event.writer.visitVarInsn(ALOAD, point);
			event.writer.visitTypeInsn(NEW, objectDes);
			event.writer.visitInsn(DUP);
			loadGetter(event);
			event.writer.visitMethodInsn(INVOKESPECIAL, objectDes, "<init>", Type.getConstructorDescriptor(constructor));
			event.writer.visitMethodInsn(INVOKEVIRTUAL, clsName, "add", "(Ljava/lang/Object;)Z");
			event.writer.visitInsn(POP);
		}
	}
	@Override
	protected void loadGetter(ASMEvent event) {
		event.writer.visitVarInsn(ALOAD, collectionEvent.itemPoint);
		if(null != toPre) toPre.loadGetter(event);
	}

	class CollectionFieldParser extends AbstractCollectionParser{

		final String objectDes;
		final Constructor<?> constructor;
		CollectionFieldParser(Class<?> collectionType, Class<?> genericsType) throws Exception {
			super(collectionType);
			constructor = genericsType.getDeclaredConstructor(entityProperty.getType());
			objectDes = Type.getInternalName(genericsType);
		}
		@Override
		public void parseProperty(ASMEvent event) throws Exception {
			if(entityProperty.getType().isPrimitive()){
				_0(event);
			}else{
				loadGetter(event);
				visitGetter(event.writer);
				Label ifnull = new Label();
				event.writer.visitJumpInsn(IFNULL, ifnull);
				_0(event);
				event.writer.visitLabel(ifnull);
			}
		}
		void _0(ASMEvent event) {
			event.writer.visitVarInsn(ALOAD, point);
			event.writer.visitTypeInsn(NEW, objectDes);
			event.writer.visitInsn(DUP);
			loadGetter(event);
			visitGetter(event.writer);
			event.writer.visitMethodInsn(INVOKESPECIAL, objectDes, "<init>", Type.getConstructorDescriptor(constructor));
			event.writer.visitMethodInsn(INVOKEVIRTUAL, clsName, "add", "(Ljava/lang/Object;)Z");
			event.writer.visitInsn(POP);
		}
		
	}
	class CollectionParser extends AbstractCollectionParser{

		CollectionParser(Class<?> clsc) {
			super(clsc);
		}

		@Override
		public void parseProperty(ASMEvent event) throws Exception {
			event.writer.visitVarInsn(ALOAD, point);
			loadGetter(event);
			visitGetter(event.writer);
			event.writer.visitMethodInsn(INVOKEVIRTUAL, clsName, "add", "(Ljava/lang/Object;)Z");
			event.writer.visitInsn(POP);
		}
	}
	
	@Override
	protected void visitGetter(MethodVisitor visitor) {
		if(null != mappedProperty){
			mappedProperty.visitMethodInsn(visitor, INVOKEVIRTUAL, false);
			if(null != convert)
				convert.visitMethodInsn(visitor, INVOKEVIRTUAL, false);
		}
	}
	
	class ArrayObjectParser extends AbstractArrayParser{
		final String objectDes;
		final Constructor<?> constructor;
		ArrayObjectParser(Class<?> genericsType) throws Exception {
			constructor = genericsType.getDeclaredConstructor(manyPropertyAccessor.getActualType());
			objectDes = Type.getInternalName(genericsType);
		}
		@Override
		public void parseProperty(ASMEvent event) throws Exception {
			event.writer.visitVarInsn(ALOAD, point);
			event.writer.visitVarInsn(ILOAD, collectionEvent.indexPoint);
			event.writer.visitTypeInsn(NEW, objectDes);
			event.writer.visitInsn(DUP);
			loadGetter(event);
			event.writer.visitMethodInsn(INVOKESPECIAL, objectDes, "<init>", Type.getConstructorDescriptor(constructor));
			event.writer.visitInsn(AASTORE);
		}

		@Override
		public void init(CollectionEvent event) {
			event.visitor.visitVarInsn(ILOAD, event.indexPoint);
			event.visitor.visitTypeInsn(ANEWARRAY, objectDes);
			super.init(event);
		}
	}
	class ArrayFieldParser extends AbstractArrayParser{
		final String objectDes;
		final Constructor<?> constructor;
		ArrayFieldParser(Class<?> genericsType) throws Exception {
			constructor = genericsType.getDeclaredConstructor(entityProperty.getType());
			objectDes = Type.getInternalName(genericsType);
		}
		@Override
		public void parseProperty(ASMEvent event) throws Exception {
			if(entityProperty.getType().isPrimitive()){
				_0(event);
			}else{
				loadGetter(event);
				visitGetter(event.writer);
				Label ifnull = new Label();
				event.writer.visitJumpInsn(IFNULL, ifnull);
				_0(event);
				event.writer.visitLabel(ifnull);
			}
		}
		void _0(ASMEvent event) {
			event.writer.visitVarInsn(ALOAD, point);
			event.writer.visitVarInsn(ILOAD, collectionEvent.indexPoint);
			event.writer.visitTypeInsn(NEW, objectDes);
			event.writer.visitInsn(DUP);
			loadGetter(event);
			visitGetter(event.writer);
			event.writer.visitMethodInsn(INVOKESPECIAL, objectDes, "<init>", Type.getConstructorDescriptor(constructor));
			event.writer.visitInsn(AASTORE);
		}

		@Override
		public void init(CollectionEvent event) {
			event.visitor.visitVarInsn(ILOAD, event.indexPoint);
			event.visitor.visitTypeInsn(ANEWARRAY, objectDes);
			super.init(event);
		}
	}
	
	class ArrayParser extends AbstractArrayParser{
		final Class<?> arrayType;
		ArrayParser(Class<?> arrayType){
			this.arrayType = arrayType;
		}
		@Override
		public void parseProperty(ASMEvent event) throws Exception {
			event.writer.visitVarInsn(ALOAD, point);
			event.writer.visitVarInsn(ILOAD, collectionEvent.indexPoint);
			loadGetter(event);
			visitGetter(event.writer);
			event.writer.visitInsn(AASTORE);
		}

		@Override
		public void init(CollectionEvent event) {
			event.visitor.visitVarInsn(ILOAD, event.indexPoint);
			event.visitor.visitTypeInsn(ANEWARRAY, Type.getInternalName(arrayType));
			super.init(event);
		}
		
	}
	class ObjectStringParser implements CollectionPropertyParser{
		final String separator;
		ObjectStringParser(){
			ArraySeparator arraySeparator = objectProperty.getAnnotation(ArraySeparator.class);
			if(null == arraySeparator){
				separator = "|";
			}else{
				separator = arraySeparator.value();
			}
		}
		@Override
		public void parseProperty(ASMEvent event) throws Exception {
			event.writer.visitVarInsn(ALOAD, point);
			loadGetter(event);
			visitGetter(event.writer);
			event.writer.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
			event.writer.visitLdcInsn(separator);
			event.writer.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
			event.writer.visitInsn(POP);
		}

		@Override
		public void init(CollectionEvent event) {
			point = event.event.assignPoint();
			event.visitor.visitTypeInsn(NEW, "java/lang/StringBuilder");
			event.visitor.visitInsn(DUP);
			event.visitor.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V");
			event.visitor.visitVarInsn(ASTORE, point);
		}

		@Override
		public void finish() {			
			loadSetter(collectionEvent.event);
			collectionEvent.visitor.visitVarInsn(ALOAD, point);
			collectionEvent.visitor.visitInsn(ICONST_0);
			collectionEvent.visitor.visitVarInsn(ALOAD, point);
			collectionEvent.visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "length", "()I");
			collectionEvent.visitor.visitInsn(ICONST_1);
			collectionEvent.visitor.visitInsn(ISUB);
			collectionEvent.visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "substring", "(II)Ljava/lang/String;");
			visitSetter(collectionEvent.visitor);
		}
		
	}
	class ObjectOtherParser implements CollectionPropertyParser{
		final String objectDes;
		final Constructor<?> constructor;
		ObjectOtherParser(Class<?> other) throws Exception{
			constructor = other.getDeclaredConstructor(manyPropertyAccessor.getType());
			objectDes = Type.getInternalName(other);
		}
		@Override
		public void parseProperty(ASMEvent event) throws Exception { }

		@Override
		public void init(CollectionEvent event) { }

		@Override
		public void finish() {
			loadSetter(collectionEvent.event);
			collectionEvent.visitor.visitTypeInsn(NEW, objectDes);
			collectionEvent.visitor.visitInsn(DUP);
			collectionEvent.visitor.visitVarInsn(ALOAD, collectionEvent.collPoint);
			collectionEvent.visitor.visitMethodInsn(INVOKESPECIAL, objectDes, "<init>", Type.getConstructorDescriptor(constructor));
			visitSetter(collectionEvent.visitor);
		}
	}
}

class ReadCipherParser extends AbstractReaderProperty{
	final Cipher cipher;
	ReadCipherParser(ASMReaderBuilder asmBuilder, String name, ObjectPropertyAccessor objectProperty,
			EntityPropertyAccessor entityProperty, PropertyReaderInitialize toPre, Cipher cipher) {
		super(asmBuilder, name, objectProperty, entityProperty, toPre);
		this.cipher = cipher;
	}

	@Override
	public final void parseProperty(ASMEvent event) throws Exception {
		MethodVisitor reader = event.writer;
		if(!setterType.isPrimitive()){
			Label ifnull = new Label();
			loadGetter(event);
			visitGetter(reader);
			reader.visitJumpInsn(IFNULL, ifnull);
			_0(event, reader);
			reader.visitLabel(ifnull);
		}else{
			_0(event, reader);
		}
	}
	
	void _0(ASMEvent event, MethodVisitor reader) throws Exception {
		/*
		 * 目前，只能支持几种类型进行加密解密
		 * 1.字符串
		 * 2.整型
		 * 3.长整型
		 * 相应的，解密也只能支持这几种类型
		 * 
		 * 以后可以根据需要，支持更多的数据类型的加密解密
		 */
		loadSetter(event);
		if(CipherGenerator.support(setterType)){
			ASMMethod encrypt = new ASMMethod(CipherGenerator.class, "decrypt", setterType);
			reader.visitTypeInsn(NEW, encrypt.path);  
			reader.visitInsn(DUP);
			reader.visitLdcInsn(cipher.value());
			reader.visitMethodInsn(INVOKESPECIAL, encrypt.path, "<init>", "(J)V", false);
			loadGetter(event);
			visitGetter(reader);
			encrypt.visitMethodInsn(reader, INVOKEVIRTUAL, false);
		}else{
			loadGetter(event);
			visitGetter(reader);
		}
		visitSetter(reader);
	}
}

/**
 * 只有String类型才能进行的解析
 * @author jackson
 *
 */
class ReadSecrecyParser extends AbstractReaderProperty{
	final Secrecy secrecy;
	final Cipher cipher;
	final ASMMethod method;
	ReadSecrecyParser(ASMReaderBuilder asmBuilder, String name, ObjectPropertyAccessor objectProperty,
			EntityPropertyAccessor entityProperty, PropertyReaderInitialize toPre, Secrecy secrecy, Cipher cipher) throws Exception{
		super(asmBuilder, name, objectProperty, entityProperty, toPre);
		this.secrecy = secrecy;
		this.cipher = cipher;
		this.method = new ASMMethod(StringHelper.class, "secrecy", String.class, char.class, int.class, int.class);
	}
	final int[] iic = {ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5};
	@Override
	public void parseProperty(ASMEvent event) throws Exception {
		MethodVisitor visitor = event.writer;
		Label ifnull = new Label();
		loadGetter(event);
		visitGetter(visitor);
		visitor.visitJumpInsn(IFNULL, ifnull);
		loadSetter(event);
		if(null != cipher){
			ASMMethod encrypt = new ASMMethod(CipherGenerator.class, "decrypt", String.class);
			visitor.visitTypeInsn(NEW, encrypt.path);  
			visitor.visitInsn(DUP);
			visitor.visitLdcInsn(cipher.value());
			visitor.visitMethodInsn(INVOKESPECIAL, encrypt.path, "<init>", "(J)V", false);
			loadGetter(event);
			visitGetter(visitor);
			encrypt.visitMethodInsn(visitor, INVOKEVIRTUAL, false);
		}else{
			loadGetter(event);
			visitGetter(visitor);
		}
		_0(visitor, secrecy.value());
		_0(visitor, secrecy.first());
		_0(visitor, secrecy.last());
		method.visitMethodInsn(visitor, INVOKESTATIC, false);
		visitSetter(visitor);
		visitor.visitLabel(ifnull);
	}
	void _0(MethodVisitor visitor, int i){
		if(i < iic.length){
			visitor.visitInsn(iic[i]);
		}else{
			visitor.visitIntInsn(BIPUSH, i);
		}
	}
}

/**
 * {@link ReadModel#OPTIMIZE}和{@link ReadModel#READABLE}两种模式都使用同一个解析器
 * @author jackson
 *
 */
class ReadCutoffParser implements PropertyParser{
	final ASMMethod method;
	final Cutoff cutoff;
	ReadCutoffParser(Cutoff cutoff)throws Exception {
		// TODO Auto-generated method stub
		this.cutoff = cutoff;
		this.method = new ASMMethod(StringHelper.class, cutoff.type().getValue(), String.class, int.class);
	}
	@Override
	public void parse(ASMAbstractProperty property, ASMEvent event) throws Exception {
		MethodVisitor visitor = event.writer;
		Label ifnull = new Label();
		property.loadGetter(event);
		property.visitGetter(visitor);
		visitor.visitJumpInsn(IFNULL, ifnull);
		property.loadSetter(event);
		property.loadGetter(event);
		property.visitGetter(visitor);
		visitor.visitIntInsn(BIPUSH, cutoff.value());
		method.visitMethodInsn(visitor, INVOKESTATIC, false);
		property.visitSetter(visitor);
		visitor.visitLabel(ifnull);
	}
}

class ReadValueParser extends AbstractReaderProperty{
	final ValueReader valueReader;
	
	ReadValueParser(ASMReaderBuilder asmBuilder, String name, ObjectPropertyAccessor objectProperty,
			EntityPropertyAccessor entityProperty, PropertyReaderInitialize toPre, ValueReader valueReader) {
		super(asmBuilder, name, objectProperty, entityProperty, toPre);
		this.valueReader = valueReader;
	}
	
	@Override
	public void parseProperty(ASMEvent event) throws Exception {
		if(!getterType.isPrimitive()){
			if(setterType.isPrimitive()){
				_0(event);
			}else{
				Label ifnull = new Label();
				loadGetter(event);
				visitGetter(event.writer);
				event.writer.visitJumpInsn(IFNULL, ifnull);
				_0(event);
				event.writer.visitLabel(ifnull);
			}
		}
	}

	private void _0(ASMEvent event) throws Exception{
		Method method = getterType.getDeclaredMethod(valueReader.value());
		loadSetter(event);
		loadGetter(event);
		visitGetter(event.writer);
		String cp = Type.getInternalName(getterType), gn = method.getName(), gd = Type.getMethodDescriptor(method);
		if(getterType.isInterface()){
			event.writer.visitMethodInsn(INVOKEINTERFACE, cp, gn, gd, true);
		}else{
			event.writer.visitMethodInsn(INVOKEVIRTUAL, cp, gn, gd, false);
		}
		visitSetter(event.writer);
	}
}

class ReadFormatParser extends AbstractReaderProperty{
	
	final Cipher cipher;
	final FormatString formatString;
	final AppendProperty[] properties;
	final int[] iic = {ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5};
	
	ReadFormatParser(ASMReaderBuilder asmBuilder, String name, ObjectPropertyAccessor objectProperty,
			EntityPropertyAccessor entityProperty, PropertyReaderInitialize toPre, FormatString formatString, Cipher cipher) {
		super(asmBuilder, name, objectProperty, entityProperty, toPre);
		this.formatString = formatString;
		this.properties = formatString.properties();
		this.cipher = cipher;
	}
	
	void _0(ASMEvent event, EntityPropertyAccessor epa){
		Method getter = epa.getter();
		if(null != epa.getEmbeddedProperty()) _0(event, epa.getEmbeddedProperty());
		event.writer.visitMethodInsn(INVOKEVIRTUAL, builder.entityPath, getter.getName(), Type.getMethodDescriptor(getter), false);
	}
	
	void _0(ASMEvent event, AppendProperty append){
		EntityPropertyAccessor epa = builder.entityDescriptor.get(append.value());
		event.writer.visitVarInsn(ALOAD, event.getterPoint); 
		_0(event, epa);
		_0(event.writer, epa.getType());
	}
	
	@Override
	public void parseProperty(ASMEvent event) throws Exception{
		int len = properties.length, il = iic.length, i = 0;
		MethodVisitor visitor = event.writer;
		loadSetter(event);
		if(formatString.type() == FormatValueType.FORMAT){
			visitor.visitLdcInsn(formatString.value());
		}else if(formatString.type() == FormatValueType.CONFIG){
			visitor.visitLdcInsn(builder.resolveEmbeddedValue(formatString.value()));
		}else{
			visitor.visitVarInsn(ALOAD, 1);
			visitor.visitLdcInsn(formatString.value());
			Method ffs = ReadEvent.class.getDeclaredMethod("findFormatString", String.class);
			visitor.visitMethodInsn(INVOKEVIRTUAL, builder.eventPath, ffs.getName(), Type.getMethodDescriptor(ffs), false);
		}
		if(len < il){
			visitor.visitInsn(iic[len]);
			il = len;
		}else{
			visitor.visitIntInsn(BIPUSH, len + 1);
		}
		visitor.visitTypeInsn(ANEWARRAY, "java/lang/Object");
		visitor.visitInsn(DUP);
		visitor.visitInsn(ICONST_0);
		if(null != cipher && CipherGenerator.support(setterType)){
			ASMMethod encrypt = new ASMMethod(CipherGenerator.class, "decrypt", setterType);
			visitor.visitTypeInsn(NEW, encrypt.path);  
			visitor.visitInsn(DUP);
			visitor.visitLdcInsn(cipher.value());
			visitor.visitMethodInsn(INVOKESPECIAL, encrypt.path, "<init>", "(J)V", false);
			loadGetter(event);
			visitGetter(visitor);
			encrypt.visitMethodInsn(visitor, INVOKEVIRTUAL, false);
		}else{
			loadGetter(event);
			visitGetter(visitor);
		}
		_0(visitor, getterType);
		for(; i < il; i++){
			visitor.visitInsn(DUP);
			visitor.visitInsn(iic[i]);
			//加字段
			_0(event, properties[i]);
		}
		for(; i < len; i++){
			visitor.visitInsn(DUP);
			visitor.visitIntInsn(BIPUSH, i + 1);
			//加字段
			_0(event, properties[i]);
		}
		visitor.visitMethodInsn(INVOKESTATIC, "java/lang/String", "format", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;", false);
		visitSetter(visitor);
	}
	
	void _0(MethodVisitor visitor, Class<?> type){
		if(type.isPrimitive()){
			if(int.class.equals(type)){
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
			}else if(long.class.equals(type)){
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
			}else if(double.class.equals(type)){
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
			}else if(float.class.equals(type)){
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
			}else if(boolean.class.equals(type)){
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
			}else if(char.class.equals(type)){
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
			}else if(short.class.equals(type)){
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
			}else{
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
			}
		}
		visitor.visitInsn(AASTORE);
	}
}

abstract class AbstractStringParser implements PropertyParser{
	//TODO 转为字符串的父类
	
	class OptionArrayParser{
		final String classPath;
		final String arrayFieldDes;
		final String offsetFieldDex;
		final String arrayFieldName;
		final String offsetFieldName;
		
		OptionArrayParser(ASMReaderBuilder builder){
			this.classPath = builder.classPath;
			this.arrayFieldDes = "[Ljava/lang/String;";
			this.offsetFieldDex = "I";
			this.arrayFieldName = builder.assignField(arrayFieldDes);
			this.offsetFieldName = builder.assignField(offsetFieldDex);
		}
		
		void putArray(MethodVisitor constructor){
			constructor.visitFieldInsn(PUTFIELD, classPath, arrayFieldName, arrayFieldDes);
		}
		
		void putOffset(MethodVisitor constructor){
			constructor.visitFieldInsn(PUTFIELD, classPath, offsetFieldName, offsetFieldDex);
		}
		
		void getArray(MethodVisitor visitor){
			visitor.visitVarInsn(ALOAD, 0);
			visitor.visitFieldInsn(GETFIELD, classPath, arrayFieldName, arrayFieldDes);
		}
		
		void getOffset(MethodVisitor visitor){
			visitor.visitVarInsn(ALOAD, 0);
			visitor.visitFieldInsn(GETFIELD, classPath, offsetFieldName, offsetFieldDex);
		}
	}

	OptionArrayParser _parseOptionArray(ASMReaderBuilder builder, ASMAbstractProperty property, int[] iic) {
		IOptionArray optionArray = property.objectProperty.getOptionArray();
		if(null == optionArray) { return null; }
		
		String[] oavs = optionArray.mergeArray();
		int offset = optionArray.offset();
		int len = oavs.length;
		
		OptionArrayParser oap = new OptionArrayParser(builder);
		MethodVisitor constructor = builder.constructor;
		constructor.visitVarInsn(ALOAD, 0);
		int il = iic.length, i = 0;
		if(len < il){
			il = len;
			constructor.visitInsn(iic[len]);
		}else{
			constructor.visitVarInsn(BIPUSH, len);
		}
		constructor.visitTypeInsn(ANEWARRAY, "java/lang/String");
		for(;i < il; i++){
			constructor.visitInsn(DUP);
			constructor.visitInsn(iic[i]);
			constructor.visitLdcInsn(oavs[i]);
			constructor.visitInsn(AASTORE);
		}
		for(;i < len; i++){
			constructor.visitInsn(DUP);
			constructor.visitVarInsn(BIPUSH, i);
			constructor.visitLdcInsn(oavs[i]);
			constructor.visitInsn(AASTORE);
		}
		oap.putArray(constructor);
		constructor.visitVarInsn(ALOAD, 0);
		if(0 <= offset && offset < iic.length){
			constructor.visitInsn(iic[offset]);
		}else if(offset == -1){
			//注意关于 "-1" 的赋值
			constructor.visitInsn(ICONST_M1);
		}else{
			constructor.visitVarInsn(BIPUSH, offset);
		}
		oap.putOffset(constructor);
		return oap;
	}
}

class ReadStringParser extends AbstractStringParser{
	
	final int[] iic = {ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5};
	
	@Override
	public void parse(ASMAbstractProperty property, ASMEvent event) throws Exception {
		MethodVisitor visitor = event.writer;
		/*
		 * 1.日期类型转为字符串
		 * 2.基本数据类型转为字符串
		 * 3.其它类型的对象转字符串
		 */
		Class<?> to = property.getterType;
		if(Date.class.equals(to)){
			Temporal temporal = ((ASMReaderProperty)property).entityProperty.getAnnotation(Temporal.class);
			String fs;
			if(null == temporal || temporal.value() == TemporalType.DATE){
				fs = "date2String";
			}else if(temporal.value() == TemporalType.TIMESTAMP){
				fs = "datetime2String";
			}else{
				fs = "time2String";
			}
			ASMMethod toString = new ASMMethod(StringHelper.class, fs, Date.class);
			property.loadSetter(event);
			property.loadGetter(event);
			property.visitGetter(visitor);
			toString.visitMethodInsn(visitor, INVOKESTATIC, false);
			property.visitSetter(visitor);
		}else{ 
			ASMReaderProperty asmrp = (ASMReaderProperty)property;
			ASMReaderBuilder builder = asmrp.builder;
			if(to.isEnum()){
				OptionArrayParser oap = _parseOptionArray(builder, asmrp, iic);
				if(null != oap){
					Label ifnull = new Label();
					property.loadGetter(event);
					property.visitGetter(visitor);
					visitor.visitJumpInsn(IFNULL, ifnull);
					property.loadSetter(event);
					oap.getArray(visitor);
					property.loadGetter(event);
					property.visitGetter(visitor);
					visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(to), "ordinal", "()I", false);
					oap.getOffset(visitor);
					visitor.visitInsn(ISUB);
					visitor.visitInsn(AALOAD);
					property.visitSetter(visitor);
					visitor.visitLabel(ifnull);
					return;//结束
				}
			}else if(int.class.equals(to)){
				OptionArrayParser oap = _parseOptionArray(builder, asmrp, iic);
				if(null != oap){
					property.loadSetter(event);
					oap.getArray(visitor);
					property.loadGetter(event);
					property.visitGetter(visitor);
					oap.getOffset(visitor);
					visitor.visitInsn(ISUB);
					visitor.visitInsn(AALOAD);
					property.visitSetter(visitor);
					return;//结束
				}
			}else if(Integer.class.equals(to)){
				OptionArrayParser oap = _parseOptionArray(builder, asmrp, iic);
				if(null != oap){
					Label ifnull = new Label();
					property.loadGetter(event);
					property.visitGetter(visitor);
					visitor.visitJumpInsn(IFNULL, ifnull);
					property.loadSetter(event);
					oap.getArray(visitor);
					property.loadGetter(event);
					property.visitGetter(visitor);
					visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
					oap.getOffset(visitor);
					visitor.visitInsn(ISUB);
					visitor.visitInsn(AALOAD);
					property.visitSetter(visitor);
					visitor.visitLabel(ifnull);
					return;//结束
				}
			}else if(boolean.class.equals(to)){
				OptionArrayParser oap = _parseOptionArray(builder, asmrp, iic);
				if(null != oap){
					property.loadSetter(event);
					oap.getArray(visitor);
					property.loadGetter(event);
					property.visitGetter(visitor);
					oap.getOffset(visitor);
					visitor.visitInsn(ISUB);
					visitor.visitInsn(AALOAD);
					property.visitSetter(visitor);
					return;//结束
				}
			}else if(Boolean.class.equals(to)){
				OptionArrayParser oap = _parseOptionArray(builder, asmrp, iic);
				if(null != oap){
					Label ifnull = new Label();
					property.loadGetter(event);
					property.visitGetter(visitor);
					visitor.visitJumpInsn(IFNULL, ifnull);
					property.loadSetter(event);
					oap.getArray(visitor);
					property.loadGetter(event);
					property.visitGetter(visitor);
					visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
					oap.getOffset(visitor);
					visitor.visitInsn(ISUB);
					visitor.visitInsn(AALOAD);
					property.visitSetter(visitor);
					visitor.visitLabel(ifnull);
					return;//结束
				}
			}
			if(to.isPrimitive()){
				//一般是不会把基本类型在数据库里定义在字符串来存储的，所以这里先判断一下是否为基本类型，就不用具体的去判断每一个基本类型是什么了
				StringDescriptor valueOf = new StringDescriptor(to);
				property.loadSetter(event);
				property.loadGetter(event);
				property.visitGetter(visitor);
				valueOf.visitMethodInsn(event.writer, INVOKESTATIC, false);
				property.visitSetter(visitor);
			} else {
				//不需要考虑这里两个字段的类型是否都为string，因为相同类型的处理不是这个类
				Label ifnull = new Label();
				property.loadGetter(event);
				property.visitGetter(visitor);
				visitor.visitJumpInsn(IFNULL, ifnull);
				property.loadSetter(event);
				property.loadGetter(event);
				property.visitGetter(visitor);
				visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(to), "toString", "()Ljava/lang/String;", false);
				property.visitSetter(visitor);
				visitor.visitLabel(ifnull);
			}
		}
	}
}